Jamot is the backend (and cockpit frontend) for a human-centered, AI-native platform where a Person or Organization can discover, manage, execute, learn from, and monetize problem-solving capabilities.
It is a universal organizational kernel — not an agent runtime, CRM, ERP, or messaging app. External systems (Letta, Honcho, Graphiti, Hermes, OpenClaw, OpenManus, Matrix, MCP, …) are replaceable implementations behind Jamot interfaces.
Jamot owns identity, relationships, permissions, organizational state, capability contracts and governance. External systems provide specialized cognition, communication, execution and knowledge infrastructure.
Source of truth:
JAMOT_SPEC.mdis the authoritative product/spec document for this repository. Design decisions and implementations must stay consistent with it.
J-01/
├── apps/console/ Next.js 16 unified console UI (CopilotKit v2, per-org branded "skins" via subdomain)
├── packages/contracts/ Shared Zod domain contracts (the single source of truth for types)
├── packages/core/ Domain layer: Drizzle schema, events, policy engine, repositories,
│ memory/knowledge, LLM + routing, apps/resolver, channels,
│ scheduler, reputation, treasury, harness, MCP
├── packages/api/ Fastify REST API + session auth + Google OAuth + RBAC
├── packages/workers/ Background processes: scheduler/heartbeats, channel adapters
│ (WhatsApp via Baileys, Matrix via matrix-js-sdk)
└── packages/sdk/ App SDK manifest types
- Backend: Node 22, TypeScript (ESM), Fastify, Drizzle + PostgreSQL 16, Redis/BullMQ, Zod
- Frontend: Next.js 16 (App Router), React 19, Tailwind v4, CopilotKit v2 (AG-UI + A2UI)
- Package manager: pnpm workspaces
- Node.js ≥ 22, pnpm ≥ 9 (
corepack enable) - Docker (for local Postgres + Redis + Synapse)
corepack enable
pnpm install
# local infrastructure (Postgres on :5433, Redis on :6379, Synapse on :8008)
docker compose up -d postgres redis
cp .env.example .env # fill in SESSION_SECRET, LLM keys, Google OAuth, etc.
# apply migrations (manual psql; see packages/core/src/migrations/)
cat packages/core/src/migrations/0001_init.sql \
packages/core/src/migrations/0002_memory_knowledge.sql \
packages/core/src/migrations/0003_reputation_treasury.sql \
packages/core/src/migrations/0004_users.sql \
| docker exec -i jamot-postgres psql -U jamot -d jamot -v ON_ERROR_STOP=1 -f -# API (http://localhost:4000) — uses Postgres when DATABASE_URL is set, else in-memory
pnpm --filter @jamot/api dev
# Console (http://localhost:3002) — set NEXT_PUBLIC_API_URL to point at the API
NEXT_PUBLIC_API_URL=http://localhost:4000 pnpm --filter @jamot/console dev
# Scheduler / heartbeat worker
pnpm --filter @jamot/workers dev:scheduler
# Channel worker (WhatsApp QR / Matrix bot) — requires credentials
pnpm --filter @jamot/workers dev:channelWhatsApp pairing: the channel worker runs a small control server that the API proxies
for the /whatsapp UI. Point the API at it via WA_WORKER_URL (defaults unset → 503).
# API .env
WA_WORKER_URL=http://localhost:3001If a session is logged out or corrupted, use the Reset pairing button in the
WhatsApp app (calls POST /api/wa/reset, which wipes the session dir and starts a
fresh QR).
WhatsApp refuses the new-pairing handshake from datacenter IPs (Render Oregon),
so no QR can be generated there — the connection loops with status=428 and no
QR ever appears. Existing sessions resume fine from the same IPs.
To pair a fresh session, run the helper from a machine on a residential/office network, then import the produced folder into the deployed worker:
pnpm --filter @jamot/workers exec tsx src/wa-pair.ts --out .wa-pairScan the printed/saved wa-qr.png with WhatsApp → Settings → Linked devices.
Once paired, upload the .wa-pair directory via the web app
(WhatsApp → Import), or post it directly:
# files: { "creds.json": "<base64>", ... }
curl -X POST https://<api>/api/wa/accounts/<id>/session \
-H "Content-Type: application/json" -H "Cookie: <session>" \
-d '{"files":{...}}'The deployed worker then resumes the session from Render's IP.
pnpm -r typecheck # typecheck all packages
pnpm -r test # run all tests (vitest)
pnpm -r build # build all packages/api/health, /actors, /people, /organizations, /spaces, /roles, /tasks, /auth (login/logout/me + /auth/google OAuth), /agents (+ /agents/import-mcp), /skills, /connectors, /capabilities, /vault, /channels, /apps (+ /apps/resolve), /memory, /knowledge, /reputation, /treasury, /routing/intent, /tasks/:id/assign.
The Organization Visual is the Vibe DREAM Configurator: a living system of
DREAM → TEAMS → HUMANS + AGENTS → RESPONSIBILITIES → TOOLS → HEARTBEATS
represented as typed graph nodes and edges, persisted in org_nodes /
org_edges (migration 0021_dream_graph.sql, schema orgNodes/orgEdges in
packages/core/src/schema/index.ts, contracts in
packages/contracts/src/dream.ts). Every mutation is written to organization
memory (events like node.created, edge.created, dream.configured,
heartbeat.fired), which the Graphiti dual-write projection mirrors.
DREAM graph endpoints (RBAC: reads = org access, writes = org admin for DREAM config / deletes, org access for node/edge mutations):
GET /organizations/:id/graph— full graph (auto-creates the org's DREAM node on first read)POST|PATCH|DELETE /organizations/:id/graph/nodes[/:nodeId]POST|DELETE /organizations/:id/graph/edges[/:edgeId]PUT /organizations/:id/dream— structured DREAM config (objective, outcomes, KPIs, constraints, timeline, capabilities, responsibilities)GET /organizations/:id/readiness— computed DREAM Readiness (never hard-coded)GET /organizations/:id/jamot—{ jamot, overall }(JAMOT = Just A Matter Of Time, operational readiness)
DREAM Readiness is computed by packages/core/src/dream/readiness.ts across
10 dimensions (dream objective, responsibility coverage, actors, teams, tools,
permissions, dependencies, heartbeats, recovery, escalation). JAMOT means the
organization is configured to continuously pursue the DREAM, detect problems,
adapt and recover. The underlying DREAM orchestration skill is platform-owned
(packages/core/src/dream/skill.ts) and not user-editable.
Org-graph Heartbeats are executed by the scheduler worker
(packages/core/src/dream/heartbeat.ts, wired in packages/workers): each due
heartbeat runs Monitor → Evaluate → Act → Verify and records
heartbeat.fired / heartbeat.detected organizational memory events (used by
the resilience/recruitment flow via the existing outreach + policy-engine
infrastructure).
See .env.example. Key vars: DATABASE_URL, SESSION_SECRET, SECRET_ENCRYPTION_KEY, OPENAI_API_KEY/ANTHROPIC_API_KEY (LLM), GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET/GOOGLE_REDIRECT_URI/FRONTEND_URL (OAuth), WHATSAPP_SESSION_DIR/MATRIX_* (channels).
Jamot keeps Postgres memories/knowledge tables as the source of truth. When
enabled, a self-hosted Graphiti MCP server
runs as a dual-write projection: every POST /api/memory is also sent to
Graphiti (episode source="json", group_id = "<scope>:<ownerId>", episode
uuid = memory id), where LLM extraction builds a temporally-aware entity/edge
graph on top of FalkorDB. Reads always come from Postgres; Graphiti mirror
failures are logged and never break the request.
Start it locally:
docker compose up -d falkordb graphiti-mcp # http://localhost:8000/mcp/ + /healthEnable with:
GRAPHITI_ENABLED=true
GRAPHITI_MCP_URL=http://localhost:8000/mcp/
OPENAI_API_KEY=... # used by Graphiti for extraction + embeddings
SEMAPHORE_LIMIT=2 # LLM concurrency; each store() triggers multiple LLM calls
Notes: Graphiti is not provisioned on Render's free tier (needs a host the API
can reach over HTTP + an LLM key). Telemetry is off by default
(GRAPHITI_TELEMETRY_ENABLED=false). The /agents/import-mcp SSRF guard is
intentionally NOT applied to GRAPHITI_MCP_URL — it is an internal,
operator-controlled endpoint, never user input.
Backend phases P1–P9 and frontend F1–F8 are implemented against the MVP boundary (Personal/Organization spaces, People, Agents, Main Manager routing, WhatsApp/Matrix/MCP, Skills, Connectors, Tasks, Memory, CopilotKit, App SDK, one external-agent import, reputation, treasury, scheduler/heartbeats). Channel + LLM connections require live credentials.
Live:
- API — https://jamot-api.onrender.com
- Web — https://jamot-web.onrender.com
- Postgres —
jamot-ts-db(oregon, basic_256mb) - Scheduler worker —
jamot-scheduler
Migrations run automatically on deploy via preDeployCommand (pnpm --filter @jamot/core exec tsx scripts/migrate.ts), tracked in a schema_migrations table.
- Create an OAuth 2.0 web application client in Google Cloud Console.
- Add authorized redirect URI:
https://jamot-api.onrender.com/api/auth/google/callback. - Set
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETon thejamot-apiservice (Dashboard → jamot-api → Environment).
GOOGLE_REDIRECT_URI and FRONTEND_URL are already set on the service.