- TypeScript - Type safety
- Next.js - Web app
- Hono - API server
- Slack Bolt - Slack bot
- OpenAI Agents SDK - Multi-agent workflows
- TailwindCSS + shadcn/ui - UI
- Drizzle + PostgreSQL - DB
- Turborepo + pnpm workspaces - Monorepo
- Ultracite - Lint/format
First, install the dependencies:
pnpm installThis project uses PostgreSQL with Drizzle ORM.
-
Make sure you have a PostgreSQL database set up.
-
Update your
apps/server/.envfile with your PostgreSQL connection details. -
Apply the schema to your database:
pnpm run db:pushThen, run the development server:
pnpm run devOpen http://localhost:3001 in your browser to see the web application. The API is running at http://localhost:3000.
Monorepo split by runtime:
apps/web: Next.js 16 app router UIapps/server: Hono API + OpenAI agent workflowsapps/slack: Slack bot (Socket Mode) calling agent APIpackages/db: Drizzle + Neon serverless client + schemapackages/env: Typed env loaders for server/web/slackpackages/config: Shared config (Biome/TS)
flowchart TB
subgraph web_group["apps/web"]
web["Next.js UI (3001)"]
web_tool_next["tool: Next.js 16 App Router"]
web_tool_ui["tool: TailwindCSS + shadcn/ui"]
end
subgraph server_group["apps/server"]
server["Hono API (3000)<br/>Agents + Routes"]
server_tool_hono["tool: Hono"]
server_tool_agents["tool: OpenAI Agents SDK"]
end
subgraph slack_group["apps/slack"]
slack["Slack Bolt (Socket)"]
slack_tool_bolt["tool: Slack Bolt"]
end
subgraph future_group["Future integrations"]
future["(Jira, Linear, Google Chat, etc.)"]
future_tool_http["tool: HTTP clients"]
end
subgraph db_group["packages/db"]
db["Drizzle + Postgres"]
db_tool_drizzle["tool: Drizzle ORM"]
db_tool_pg["tool: PostgreSQL (Neon)"]
end
web -->|HTTP| server
slack -->|HTTP| server
future -.->|HTTP| server
server -->|DB| db
style future fill:#e0e7ff,stroke:#6366f1,stroke-dasharray: 5 5,color:#000
Modular Architecture: The agent API is designed to be integration-agnostic. Any client can call the HTTP endpoints, making it easy to add new integrations like Jira, Linear, Google Chat, or any other platform that can make HTTP requests.
- Web calls API via
NEXT_PUBLIC_SERVER_URL. - API exposes agent endpoints and orchestrates multi-agent flows.
- Slack bot receives messages, stores thread context, calls agent API, replies in thread.
- Learnings and thread history persist in Postgres via Drizzle.
- Orchestrator: tool-calls triage, memory, learning, vercel logs.
- Sequential: triage -> memory -> solution -> validator -> learning.
- Memory: fetch recent learnings from DB.
Orchestrator:
flowchart TB
req([request]) --> orch[Orchestrator]
orch --> orch_tool["tool: OpenAI model"]
orch --> triage[triage_agent]
triage --> triage_tool["tool: gh_create_issue?"]
orch --> memory["memory_agent<br/>DB"]
memory --> memory_tool["tool: db_read"]
orch --> learning["add_learning_agent<br/>DB"]
learning --> learning_tool["tool: db_write"]
orch --> logs[vercel_inspect_logs]
logs --> logs_tool["tool: Vercel Logs API"]
orch --> res([response])
Sequential:
flowchart TB
issue([issue]) --> triage
triage --> triage_tool["tool: gh_create_issue?"]
triage --> memory[memory]:::db
memory --> memory_tool["tool: db_read"]
memory --> solution
solution --> solution_tool["tool: OpenAI model"]
solution --> validator
validator --> validator_tool["tool: OpenAI model"]
validator --> learning[learning]:::db
learning --> learning_tool["tool: db_write"]
learning --> response([response])
classDef db fill:#f3f4f6,stroke:#9ca3af,color:#111827;
- Set
HERMES_AGENT_TRACE_CONSOLE=1to print agent traces to console.
POST /agents/orchestratorbody{ "prompt": string }->{ result }POST /agents/triagebody{ "incident": string }->{ result }POST /agents/memorybody{ "question": string }->{ result }POST /agents/sequentialbody{ "issue": string }->{ issue, triage, memory, solution, valid, notes }
learnings: issue + solution memory.threads: external thread metadata (Slack).thread_messages: per-thread message log.
Server (apps/server):
DATABASE_URLCORS_ORIGIN(optional)
Web (apps/web):
NEXT_PUBLIC_SERVER_URL
Slack (apps/slack):
SLACK_BOT_TOKENSLACK_APP_TOKENAGENT_SERVER_URL
- Check:
pnpm run checkorpnpm dlx ultracite check - Fix:
pnpm run fixorpnpm dlx ultracite fix
hermes/
├── apps/
│ ├── web/ # Frontend application (Next.js)
│ └── server/ # Backend API (Hono)
│ └── slack/ # Slack bot (Bolt)
├── packages/
│ ├── db/ # Drizzle + schema
│ ├── env/ # Typed env config
│ ├── config/ # Shared config
pnpm run dev: Start all applications in development modepnpm run build: Build all applicationspnpm run dev:web: Start only the web applicationpnpm run dev:server: Start only the serverpnpm run check-types: Check TypeScript types across all appspnpm run db:push: Push schema changes to databasepnpm run db:studio: Open database studio UIpnpm run check: Run Biome formatting and linting
This project was created with Better-T-Stack, a modern TypeScript stack that combines Next.js, Hono, and more.
