Skip to content

Installing and Running Locally

Note: To open links in a new tab, use Ctrl+Click (Windows/Linux) or Cmd+Click (macOS).

The repository ships several services. Most of the time you only need a subset:

Want to … Run
Use the legacy R Shiny app app/ — Section 2 below
Develop the user-facing portal portal/ — Section 3
Develop the MCP tools / artifact API fprspy/ — Section 4
Run a full local stack (portal + fprspy + engine) VS Code task — Section 5

All sections assume you've cloned the repo and have the prerequisites for the service(s) you want to run.


1. Prerequisites

You only need the prerequisites for the service(s) you intend to run.

1.1 Git

Use GitHub Desktop or the Git CLI (Git for Windows, Homebrew on macOS). Then clone:

git clone https://github.com/Founders-Pledge-Research-Team/ResearchStrategy.git

Or download a ZIP from the GitHub UI (CodeDownload ZIP).

1.2 R + RStudio (for app/ and engine/)

  • R 4.0 or newer.
  • RStudio (optional, recommended).

1.3 Node.js (for portal/)

  • Node 24 — matches the production image (node:24-alpine). With nvm: nvm install 24 && nvm use 24, or nvm use to read portal/.nvmrc.
  • npm ships with Node.

1.4 Python + uv (for fprspy/)

  • Python 3.11+ (uv can install/manage it for you).
  • uv (brew install uv). uv keeps the virtualenv in-project by default (fprspy/.venv).

1.5 Credentials (optional but usually needed)

  • A single gitignored repo-root .env holds local config + secrets (AWS creds for the S3 Tigris store, etc.). Copy the committed .env.example (the master inventory of every var across services) to .env and fill it in. The R packages load it via each package's .Rprofile (readRenviron("../.env")), fprspy loads it via python-dotenv, and the VS Code tasks source .env and export FPRS_STORAGE_TYPE=s3 so artifacts read/write S3 rather than the local filesystem. The portal reads its own portal/.env (copy portal/.env.example).
  • keys/gcpserviceaccount.json (Google service account JSON) is needed for the portal's knowledge-pack ingestion and the fprspy MCP's Google Sheets reader.

2. Legacy Shiny app (app/)

This is the original UI; it does not need the portal, fprspy, or the engine API.

  1. Open R/RStudio at the repo root (ResearchStrategy.Rproj in RStudio).
  2. Install the R dependencies with pak, in dependency order (store → engine → app):
    install.packages("pak")
    pak::local_install_deps("store")
    pak::local_install_deps("engine")
    pak::local_install_deps("app")
    
  3. Restart the R session (RStudio: SessionRestart R).
  4. Run the app:
    fprsapp::run_app()
    

You can also use the VS Code task Run Shiny App (runs Rscript dev/dev_run_app.R).


3. Portal (portal/)

The Next.js portal is the active product surface. For the chat + artifact cards to work end-to-end you'll usually also want the engine (Section 2 / VS Code task Run Engine API) and fprspy (Section 4) running locally — or you can point at the deployed services via the env vars below.

3.1 Install

cd portal
nvm use 24   # if you use nvm (or `nvm use` — portal/.nvmrc pins it)
npm install

3.2 Environment

Copy the example and fill in the keys you need:

cp .env.example .env

Minimum for a working local portal:

Variable Purpose
ANTHROPIC_API_KEY Chat assistant.
MOCK_USER_EMAIL / MOCK_USER_NAME Local mock-auth user (NextAuth bypass).
MCP_URL fprspy MCP HTTP endpoint (default http://localhost:8765/mcp).
FPRS_ENGINE_URL + FPRS_ENGINE_BEARER Engine plumber API (defaults: http://localhost:8001, dev).
FPRSAPP_URL Used for legacy result deeplinks (the deployed Shiny is fine).

Postgres is optional locally — if DATABASE_URL is unset, the portal falls back to PGlite (in-process Postgres-compatible) so you can run with no DB setup. To use a real Postgres, point DATABASE_URL at it and run:

npm run db:push    # or: npm run db:migrate
npm run db:seed    # optional

3.3 Run

npm run dev

Portal serves on http://localhost:3001. VS Code task: Run Portal (Next.js dev).


4. fprspy (MCP + Artifact API) (fprspy/)

fprspy is one Python package serving two HTTP roles. They can run as one process (fprspy-serve) or as two (fprspy-mcp + fprspy-artifacts).

4.1 Install

From the repo root:

uv sync --directory fprspy --all-extras

(uv keeps the virtualenv in-project by default, so this creates fprspy/.venv without any extra config.)

4.2 Environment

fprspy reads artifacts from the same store the engine writes to. For the S3 (Tigris) store, source the repo-root .env and export FPRS_STORAGE_TYPE=s3 before launching — the VS Code tasks do this for you. For a local filesystem store (default), no env is required.

Optional: - FASTMCP_PORT (MCP port, default 8765). - FPRSPY_ARTIFACTS_PORT (artifacts FastAPI port, default 8088). - FPRS_GSHEETS_CREDENTIALS=keys/gcpserviceaccount.json for the Google Sheets MCP tool.

4.3 Run

Unified (one process, recommended for local stack):

uv run --directory fprspy fprspy-serve

Separate processes:

uv run --directory fprspy fprspy-mcp         # MCP server (port 8765)
uv run --directory fprspy fprspy-artifacts   # artifacts API (port 8088)

VS Code tasks: Run Python MCP Server (local) and Run fprspy Artifacts API (local).


5. Full local stack (VS Code task)

.vscode/tasks.json defines a composite task that starts MCP + Engine + Artifacts + Portal in parallel:

Start Portal Stack (MCP + Engine + Artifacts + Portal)

From VS Code: Cmd/Ctrl-Shift-PTasks: Run Task → pick the above. It launches:

  • Run Python MCP Server (local) — fprspy MCP on :8765
  • Run Engine API (local, for portal) — engine plumber on :8001
  • Run fprspy Artifacts API (local) — artifacts FastAPI on :8088
  • Run Portal (Next.js dev) — portal on :3001

Make sure the repo-root .env and portal/.env are populated first (Sections 1.5 and 3.2).


Keeping the app up to date

Pull, reinstall dependencies for the services you use, and restart:

git pull
# R (store + engine + app):
Rscript -e 'pak::local_install_deps("store"); pak::local_install_deps("engine"); pak::local_install_deps("app")'
# Portal:
( cd portal && npm install )
# fprspy:
uv sync --directory fprspy --all-extras

In RStudio, use SessionRestart R and re-run fprsapp::run_app().