Open-source desk research agent by HeySalad
Ask a question → cook a structured research pass → get one synthesized brief.
One brief. Deep as the dish.
npx @heysalad/chicago scaffold ·
Release train ·
Contributing ·
Security
auth → ask → clarify → cook → deliver → critique → share (PDF / email)
flowchart LR
A[Auth wall] --> Q[Ask]
Q --> C[Clarify]
C --> P[Cook pipeline]
P --> D[One brief]
D --> S[Share PDF / Email]
| Step | What you see |
|---|---|
| Auth | Access-code wall (or Cloudflare Access in production) |
| Ask | Type or speak a question in the composer |
| Clarify | A couple of quick checks so the brief hits the right lens |
| Cook | Staged research (discover → define → develop → gather → extract → deliver) |
| Deliver | One editorial brief — summary, findings, gaps, next steps |
| Cite | Chicago 17th notes-bibliography style ([1] → bibliography) |
| QA | A critique pass can rewrite once if the brief needs work |
| Share | PDF (print), email, Markdown, HTML, copy |
Demo mode works with no API keys. Live mode uses Cloudflare Workers AI, OpenRouter, and/or NVIDIA via a local Vite proxy (/api/llm/chat), with optional Tavily for web sources.
Brand kit lives in public/brand/ (deep-dish mark + Chicago six-point star, HeySalad cherry #ed4c4c, Figtree).
Docs
| Guide | Contents |
|---|---|
| docs/INSTALL.md | Full install |
| docs/architecture.md | Diagrams + what each part does |
| docs/cloudflare-setup.md | Workers AI, Whisper, Pages, Access |
| docs/openrouter-setup.md | OpenRouter keys + models |
| docs/auth-and-sharing.md | Auth wall + PDF / email share |
| docs/eve-integration.md | Eve runtime overview |
| docs/eve-cloudflare.md | Eve + Cloudflare AI Gateway (GLM 5.2) |
| prompts/ | Clone-and-adjust skill prompts |
- Screenshots
- How it works
- What you get
- Quick start (local)
- Modes: demo vs live
- Environment variables
- Using the app
- Project layout
- Hosting how-tos
- Security notes
- Roadmap
- Where to publish this repo
- Contributing
- Scripts
- License
| Piece | Description |
|---|---|
| Auth wall | Shared access code (SPA) + Cloudflare Access docs for SSO |
| Research pipeline | Clarify → cook stages → deliver → optional critique rewrite |
| Output | One brief: summary, reframed question, narrative, findings, gaps, next steps, confidence |
| Share | PDF (Save as PDF), email (mailto:), Markdown, HTML, clipboard |
| Citations | Chicago 17th notes-bibliography |
| Voice input | Mic → Cloudflare Whisper transcription (live) |
| Demo mode | Works with no API keys |
| Live mode | Cloudflare Workers AI, OpenRouter, and/or NVIDIA (+ optional Tavily) |
| Eve runtime | Durable sessions (Vercel Workflows) + isolated gather (Vercel Sandbox) under agent/ |
| Prompts | Editable skills in Admin + prompts/*.md for forks |
| Admin | Test models, edit prompts, manage users (local studio) |
| UI | HeySalad Chicago research desk — mark, wordmark, cherry accent |
Requires Node.js 20+ (18+ may work; 20 recommended). Full walkthrough: docs/INSTALL.md.
git clone https://github.com/Hey-Salad/AgentChicago17B.git
cd AgentChicago17B
npm install
cp .env.example .env
# set VITE_APP_ACCESS_CODE=... and at least one LLM provider
npm run devOpen the URL Vite prints (default: http://127.0.0.1:5173).
Unlock the auth wall, then try a starter prompt. Demo mode works with no LLM keys; for live synthesis configure Cloudflare and/or OpenRouter (or NVIDIA) — see docs/cloudflare-setup.md and docs/openrouter-setup.md.
Restart npm run dev after any .env change.
| Mode | When | What happens |
|---|---|---|
| Demo | No usable LLM config, or live call fails | Curated / fallback brief so the UI always has something to show |
| Live | LLM configured via Vite proxy | Model returns JSON for one brief; optional Tavily adds real web sources |
Important architecture detail for hosting:
- The browser talks to
POST /api/llm/chat - In local dev, that route is served by a Vite middleware proxy (
vite.config.ts) so API keys stay off the client and CORS is avoided - A static SPA upload alone does not include that proxy — demos still work; live mode needs the same endpoint on your host (Worker / Function / Cloud Function / etc.)
Browser UI → /api/llm/chat (your server) → Cloudflare Workers AI / OpenRouter / NVIDIA
→ /api/stt/transcribe (Whisper, optional)
→ Tavily (optional, for sources)
Copy .env.example → .env (never commit .env).
| Variable | Required for | Purpose |
|---|---|---|
VITE_AUTH_REQUIRED |
Auth wall | Default true; set false behind Cloudflare Access |
VITE_APP_ACCESS_CODE |
Auth wall | Shared team unlock code |
VITE_CF_API_KEY |
Cloudflare live models + Whisper | Workers AI API token |
VITE_CF_BASE_URL |
Cloudflare live models | https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/ai/v1 |
VITE_OPENROUTER_API_KEY |
OpenRouter models | Key from openrouter.ai/keys |
VITE_OPENROUTER_BASE_URL |
OpenRouter | Default https://openrouter.ai/api/v1 |
VITE_LLM_PROVIDER |
Ambiguous slugs | Force cloudflare / openrouter / nvidia |
VITE_LLM_MODEL |
Default model picker | e.g. @cf/zai-org/glm-5.2 or anthropic/claude-sonnet-4 |
VITE_LLM_API_KEY |
NVIDIA live models | NVIDIA Build API key |
VITE_LLM_BASE_URL |
NVIDIA live models | Usually https://integrate.api.nvidia.com/v1 |
VITE_TAVILY_API_KEY |
Live web sources | Optional; without it, live mode synthesizes from model knowledge |
Step-by-step: Cloudflare · OpenRouter · Auth & sharing
Note: variables prefixed with
VITE_are visible to the Vite client build unless only the server proxy reads them. Today the proxy loads env on the Vite server. For production hosts, store secrets in the platform secret store and do not bake provider keys into the frontend bundle.
- Unlock the auth wall with your access code
- Open the empty state — pizza mark, AgentChicago17B, “Open source by HeySalad”
- Pick a starter or type / speak a research question
- Answer clarify checks (or skip) so the brief has the right lens
- Choose a model (Cloudflare, OpenRouter, or NVIDIA)
- Watch the cook stages, then read the synthesized brief + bibliography
- Share → PDF / Email / Markdown
- Optional: Admin → Test models / Edit prompts (or edit files in
prompts/)
Suggested demo questions:
- What is AgentChicago17B?
- How should desk research become one brief?
- Chicago as a research environment
AgentChicago17B/
├── src/
│ ├── App.tsx # Shell: sidebar, empty state, composer, results
│ ├── App.css / index.css # Brand tokens + layout
│ ├── agent/ # Pipeline, intent, critique, Chicago cites, models
│ ├── admin/ # Skills store + dashboard pages
│ ├── components/ # Brief, sources, cooking status, admin UI
│ └── hooks/ # Voice input, etc.
├── public/brand/ # Official mark + lockup assets
├── agent/ # Eve durable agent (Workflows + Sandbox)
├── prompts/ # Clone-and-adjust skill prompts
├── docs/ # Install, architecture, Eve, Cloudflare, OpenRouter
├── vite.config.ts # Dev server + /api/llm/chat (+ /eve proxy)
├── .env.example
└── README.md
npm install
# Terminal A
npm run eve
# Terminal B
npm run devThen Admin → Eve desk. Details: docs/eve-integration.md.
Legend used below:
| Badge | Meaning |
|---|---|
| Ready now | Follow steps and it works with current code |
| UI ready / proxy TBD | You can ship the static UI today; live LLM needs a /api/llm/chat adapter on that platform (same contract as the Vite proxy) |
| Planned | Documented target; implementation landing as the open-source surface grows |
Every cloud path starts the same:
npm install
npm run build
# output: dist/Status: Ready now
Best path for contributors and demos.
npm install
cp .env.example .env # optional for live mode
npm run dev # http://127.0.0.1:5173Production-like local check:
npm run build
npm run preview
vite previewserves the static build. Live LLM still depends on the dev proxy unless you add a separate API process. For full live demos, usenpm run dev.
Status: Ready now (Worker API + selectable auth + D1/KV/R2/Vectorize — see docs/product-map.md)
Configure .env with VITE_CF_* as above and run locally. Models prefixed @cf/ route through the Vite proxy to Workers AI.
npm run chicago -- onboard # interactive questions (QuickStart / Advanced)
npm run chicago -- provision # create D1 / KV / R2 / Vectorize
# Create D1 / KV / R2 / Vectorize, paste ids into wrangler.toml
npm run cf:deploy # or: npm run chicago -- deployOr via the published CLI:
npx @heysalad/chicago scaffold my-agent
cd my-agent && npm install
npx @heysalad/chicago onboardWorker entry: workers/api/src/index.ts. Auth modes: docs/auth-modes.md.
Local without Wrangler: npm run dev serves an in-memory /api/* shim for sessions, cache, RAG, and memory.
Status: UI ready / proxy TBD
- Import the GitHub repo in vercel.com
- Framework preset: Vite
- Build command:
npm run build - Output directory:
dist - Deploy
Demo UI works.
For live mode, add a Serverless/Edge Function that mirrors the Vite proxy:
api/llm/chat.ts # POST → NVIDIA or Cloudflare OpenAI-compatible endpoint
Store CF_API_KEY / NVIDIA_API_KEY in Vercel Project → Settings → Environment Variables (server-only, not VITE_ unless you intentionally expose them).
Status: UI ready / proxy TBD
Hosting (static UI)
npm install -g firebase-tools
firebase login
firebase init hosting
# public directory: dist
# single-page app: Yes
npm run build
firebase deploy --only hostingDemo UI works.
Live mode: use Cloud Functions (2nd gen) or Cloud Run for POST /api/llm/chat, then rewrite in firebase.json:
{
"hosting": {
"public": "dist",
"rewrites": [
{ "source": "/api/**", "function": "llmChat" },
{ "source": "**", "destination": "/index.html" }
]
}
}Keep provider keys in Functions secrets / Google Secret Manager.
Status: UI ready / proxy TBD
Common pattern:
| Layer | Service |
|---|---|
Static UI (dist/) |
S3 + CloudFront |
POST /api/llm/chat |
API Gateway + Lambda (Node 20) or CloudFront → Lambda@Edge / Function URL |
Outline:
npm run build- Upload
dist/to an S3 website bucket (or sync for CloudFront origin) - Implement Lambda with the same JSON body the Vite proxy accepts (
model,messages,temperature,max_tokens) - Put keys in Secrets Manager or Lambda env (encrypted)
- Point CloudFront behaviors:
/api/*→ API, default → S3
Amplify Hosting is also fine for the static UI; still attach a backend route for live LLM.
Status: UI ready / proxy TBD
| Layer | Service |
|---|---|
| Static UI | Firebase Hosting, Cloud Storage + HTTPS Load Balancer, or Firebase as above |
| API proxy | Cloud Functions (2nd gen) or Cloud Run |
Outline (Cloud Run):
npm run build
# container: nginx/Caddy serving dist + small Node proxy, OR
# separate Cloud Run service for /api/llm/chat and frontend on Firebase/GCS
gcloud run deploy agentchicago-api --source ./api --allow-unauthenticated=falsePrefer authenticated invoke + Identity-Aware Proxy for private demos; public demos should still keep LLM keys only on the API service.
Status: UI ready / proxy TBD
| Layer | Service |
|---|---|
| Static UI | Azure Static Web Apps or Blob Storage static website + CDN |
| API proxy | Azure Functions (Node) or Container Apps |
Static Web Apps
- Connect the GitHub repo
- App location:
/ - Output location:
dist - Api location (when ready):
apiwith a function at/api/llm/chat
Store secrets in SWA / Key Vault application settings (server-side).
| Target | Static UI | Demo briefs | Live LLM today |
|---|---|---|---|
Local (npm run dev) |
✅ | ✅ | ✅ (Vite proxy) |
| Cloudflare Pages | ✅ | ✅ | 🔧 add Pages Function / Worker |
| Vercel | ✅ | ✅ | 🔧 add Serverless/Edge Function |
| Firebase Hosting | ✅ | ✅ | 🔧 add Cloud Function / Run |
| AWS (S3/CloudFront) | ✅ | ✅ | 🔧 add Lambda / API Gateway |
| Google Cloud | ✅ | ✅ | 🔧 add Cloud Function / Run |
| Azure Static Web Apps | ✅ | ✅ | 🔧 add Azure Function |
The open-source goal is one shared /api/llm/chat contract so each host only needs a thin adapter.
- Never commit
.env, API tokens, or account-specific URLs with secrets - Do not ship provider keys inside the browser bundle for production
- Prefer platform secret stores (Workers secrets, Vercel env, Secret Manager, Key Vault, Secrets Manager)
- Browser BYOK is fine for local demos; production should always proxy
- Rotate any key that was pasted into chat logs or committed by mistake
- Desk research pipeline → one synthesized brief
- Intent clarify + critique QA pass
- Chicago 17th citations
- Auth wall (access code) + Cloudflare Access docs
- Share brief as PDF / email / Markdown / HTML
- Demo mode without keys
- Live LLM via Vite proxy (Cloudflare Workers AI + OpenRouter + NVIDIA)
- Optional Tavily gathering + Whisper voice input
- Admin studio + cloneable
prompts/ - HeySalad Chicago research-desk UI + brand kit
- Install + architecture docs with diagrams
- Eve agent + Vercel Workflows/Sandbox integration (
agent/, Admin Eve desk)
- Shared API adapter — reference
/api/llm/chatfor Cloudflare, Vercel, Firebase, AWS, GCP, Azure - Unify desks — stream Eve briefs into the classic SynthesisBrief UI
- Real identity — SSO-backed users, saved research, team workspaces
- Server email — optional transactional send (vs mailto)
- Eval harness — brief quality checks against golden questions
- Source connectors — beyond Tavily (docs, Notion, Drive)
- Multi-user orgs, roles, audit trail
- Streaming synthesis UI
- Pluggable tool registry
- Self-host one-click templates
Push the canonical project to the HeySalad organization (for example Hey-Salad/AgentChicago17B), not only your personal GitHub account.
| Place | Use it for |
|---|---|
| HeySalad org | Official open-source home, README clone URL, issues, releases, brand credit |
| Personal account | Optional private WIP or a fork while you’re experimenting |
Practical workflow:
- Create (or transfer) the repo under Hey-Salad
- Add the org remote and push
mainthere - Keep a personal fork only if you want a sandbox
You do not need a separate “README repo” — the README lives in this project and ships with whatever remote is the source of truth (preferably the org).
- Fork from the HeySalad org repo (or open a PR from a branch)
npm installnpm run dev- Keep PRs focused: UI / brand, pipeline / prompts, host adapters
- Do not commit secrets
- Run
npm test,npm run lint, andnpm run buildbefore opening a PR
| Command | Purpose |
|---|---|
npm run dev |
Local app + LLM / STT proxy + in-memory sessions/RAG API |
npm run build |
Typecheck + production dist/ |
npm run preview |
Preview static build |
npm test |
Regression harness |
npm run lint |
Lint with oxlint |
npm run chicago -- <cmd> |
Instance CLI — onboard / configure / provision / deploy / doctor |
npm run cf:dev |
Wrangler Worker + assets |
npm run cf:deploy |
Build + Wrangler deploy |
Product map (auth adapters, D1/KV/R2/Vectorize, CLI): docs/product-map.md.
Using a deployed desk: docs/using-chicago.md.
Deploy your own on Cloudflare: docs/cloud-deploy.md.
MIT — see LICENSE.
![]()
AgentChicago17B — open source by HeySalad
Desk research that ends in one brief.





