This repo is designed to stay safe-by-default while still supporting deliberate live validation.
smoke: no network, no Exa billing, mocked responses onlylive: real Exa API calls, requiresEXA_API_KEY, can incur billingauto: resolves toliveonly whenEXA_API_KEYis configured; otherwise falls back tosmoke
- Use
smokefor development, CI, docs walkthroughs, and regression checks. - Use
liveonly for explicit manual validation when you want to inspect real API behavior. - Keep human review in the loop for any operational interpretation of results, even in
live.
- User-facing
researchremains a shipped workflow name in the CLI, API, and frontend, but the Exa transport is/searchwithtype="deep-reasoning". - Do not describe or implement a live Exa
/researchendpoint for this repo unless the vendor surface changes and is explicitly revalidated. - Freshness controls should be expressed through
contents.maxAgeHours, including--freshness always-liveor--max-age-hours 0for always-live behavior. - Outgoing request payloads must not emit deprecated
livecrawl,highlightsPerUrl,numSentences,startCrawlDate, orendCrawlDatefields. - Cost estimates use centralized, overrideable pricing assumptions and should not be described as exact live billing unless live Exa
costDollarsfields validate the run. Do not claim grounding quality, S3, Postgres, or deployed validation until those paths actually run.
- Rebuilt an isolated virtual environment and installed with
python -m pip install --no-user -e '.[dev,api]' - Passed
python -m pytest -q,python -m ruff check ., andpython scripts/run_live_validation.py --mode smoke - Booted the FastAPI app locally and verified
/healthand/docs - Booted the Next.js frontend locally and verified Search, Answer, Research, and My Work against the local backend
- Did not revalidate
livemode, S3 artifact storage, or Postgres-backed usage/run persistence
Issue #63 adds a narrow real-service validation command for the pilot persistence baseline:
python scripts/run_pilot_persistence_validation.py --output live-validation-artifacts/pilot-s3-postgres-validation.jsonThis path is deliberately smoke-mode for Exa traffic, but real for persistence. It must run with PILOT_RUN_STORE=postgres, PILOT_POSTGRES_URL, PILOT_ARTIFACT_STORE=s3, PILOT_S3_BUCKET, and a validation-scoped PILOT_S3_PREFIX. AWS credentials must be available to boto3 with upload/list access to the selected prefix. If API auth is enabled, PILOT_VALIDATION_API_KEY must contain a valid pilot API key.
The command fails closed unless /health reports run_store=postgres and artifact_store=s3, one /api/search smoke request completes, the matching run is visible through /api/me/runs, the persisted artifact_location is the selected s3:// prefix, and the S3 prefix lists at least the persisted artifact count.
This command does not create infrastructure, deploy the app, redesign migrations, or prove live Exa behavior. Do not claim S3/Postgres validation passed unless this command exits 0 against real external Postgres and S3 services.
After replacing the placeholder Exa API key, a narrow live CLI rerun validated only research and structured-search grounding behavior:
- Live
researchcompleted againsthttps://api.exa.ai/searchwithrequest_id=7f2b06e5b419f4ca182d1144c0c9e4d9,actual_cost_usd=0.015, and 5 results, but the response did not includeoutput.contentoroutput.grounding. - Live
structured-searchcompleted withrequest_id=c4e750dd01ad3bb1ce78621663609d59,actual_cost_usd=0.012,output.content,output.grounding, andgrounding_count=26. - The structured-search
report.mdrenderedGrounding / Source Review, confirming the current Markdown path surfaces preserved grounding metadata.
This was not a frontend, S3, Postgres, deployment, monitoring, or broad production validation.
- Smoke runs preserve the same artifact shape as live runs whenever possible.
- Workflow-specific payloads remain additive. Existing JSON and JSONL contracts should not be rewritten just because a new export is added.
- Every run records runtime execution metadata in
config.json,summary.json, andmanifest.jsonso reviewers can distinguish smoke artifacts from live artifacts. - Manual live validation should assert the expected artifact contract for each workflow before the run is treated as successful.
- Contract checks should confirm the presence of the workflow-specific artifact file plus the core summary output for that run.
- Single-workflow live validations should also assert that the emitted JSON payload includes a non-empty
request_id.
- CI should stay smoke-only by default.
- CI is allowed to run lint, pytest, and the notebook smoke runner.
- Live API validation should remain an explicit manual workflow until its scope, spend guardrails, secrets handling, and artifact assertions are documented more tightly.
- The manual live-validation path is
.github/workflows/live-validation.yml, backed byscripts/run_live_validation.py. - The runner writes a
validation_summary.jsonfile plus the underlying workflow artifacts for review; these outputs are runtime artifacts and should not be committed. - The manual workflow should fail closed on a missing
EXA_API_KEYin live mode and should keep comparison validation opt-in.
- Cached reruns should not re-bill.
- Live validation should stay bounded to small, intentional runs.
- Comparison validation should stay opt-in because it performs multiple real search calls.
- Public/professional info only.
- No address hunting, contact harvesting, or operational use without human review.
This section clarifies what belongs in the repo now versus what should be deferred to platform or infrastructure layers.
| Component | Rationale |
|---|---|
Workflow engine (src/exa_demo/) |
Core business logic; tested; stable |
| CLI + notebook interfaces | Existing user surfaces |
| SQLite cache + budget ledger | Local dev and smoke mode persistence |
| Benchmark fixtures and evaluation | Domain-specific; tightly coupled to workflows |
| Thin FastAPI wrapper | Thin adapter over existing workflows; belongs with the code it wraps |
| Frontend app | Product UI; lives in-repo as frontend/ until scale demands separation |
| Component | Rationale |
|---|---|
| Container orchestration (ECS/K8s) | Deploy-time concern; not needed for pilot |
| Infrastructure as code (Terraform/CDK) | Separate repo or separate directory once pilot is validated |
| Secret management (AWS Secrets Manager, Vault) | Environment-level concern; use env vars for pilot |
| CDN / edge config | Vercel handles this for frontend; backend can add later |
| Log aggregation / APM (Datadog, etc.) | Platform-level; structured logging in-repo is sufficient for pilot |
| CI/CD pipeline for production deploy | GitHub Actions handles smoke CI; production deploy pipeline is a Level 2+ concern |
- Do not add infrastructure-as-code to the repo until the pilot architecture is validated with real users.
- Keep the API wrapper thin - it should delegate to existing workflow functions, not duplicate logic.
- Frontend and backend can share a monorepo during pilot. Separation is a Level 3 concern.
- Auth should start as simple middleware in the API layer, not as a separate service.
- Do not blur additive S3/Postgres code paths with the current validated local smoke path unless they have been explicitly revalidated end to end.