Skip to content

Repository files navigation

Junto

A keyboard-first task tracker — with a built-in MCP server so Claude can manage your work.

Boards, lists, subtasks, labels, comments and a ⌘K command palette — plus full-text & semantic search, realtime sync, and a PWA. 100% open-source, runs entirely on free tiers.

SvelteKit Cloudflare Workers Supabase TypeScript MCP License: AGPL v3

Live demo · Quick start · Architecture · Connect Claude

Junto sign-in

Junto — Spanish for "together", and the name of Benjamin Franklin's 1727 club for mutual improvement. It's a personal, Linear/Huly-style tracker that keeps your projects, tasks and discussions in one fast, keyboard-driven space — and exposes them to AI assistants over the Model Context Protocol.


Features

  • ⌨️ Keyboard-first speed layer — a ⌘K command palette (fuzzy search over actions, projects and tasks) and shortcuts (c new task, b/l board/list, g h home, ? help). A Huly-style composer creates tasks with inline status/priority/due/label pills.
  • 🗂 Full tracker — projects, tasks, board & list views, drag-to-reorder, subtasks, labels, due dates and filters. A view-first task detail with inline editing.
  • 💬 Comments & activity — threaded comments and an append-only activity feed per task and workspace-wide.
  • 🔎 Search — Postgres full-text search everywhere, plus optional pgvector + local Ollama semantic search.
  • 🤖 MCP server — a standalone Worker that lets Claude & Cursor list, create and update tasks. Changes stream back into the UI live.
  • ⚡ Realtime & optimistic UI — every change applies instantly and syncs across tabs/devices via Supabase Realtime.
  • 🔐 Auth & RLS — magic-link auth with Postgres Row-Level Security (defense-in-depth) and manual ownership checks on every endpoint.
  • 📱 PWA — installable, with an offline shell.

Tech stack

Concern Choice
Framework SvelteKit · Svelte 5 (runes) · TypeScript (strict)
Deploy Cloudflare Workers (@sveltejs/adapter-cloudflare)
Database Supabase Postgres · Drizzle ORM · pgvector
Auth Supabase Auth (magic-link) + Row-Level Security
UI Tailwind CSS v4 · shadcn-svelte · lucide · Inter · dark-default
Realtime Supabase Realtime
AI / MCP Model Context Protocol over Streamable HTTP · local Ollama
Tooling pnpm workspaces · Zod

Architecture

A pnpm monorepo of four workspaces. The split exists so the web app and the MCP server share identical domain rules (enums, Zod validation, DB queries) and can never drift.

apps/
  web/     # SvelteKit app (UI + JSON API)          → Cloudflare Worker
  mcp/     # MCP server (POST /mcp, bearer auth)     → Cloudflare Worker
packages/
  core/    # framework-free enums, Zod schemas, Ollama embedding helper
  db/      # Drizzle schema, queries, migrations, RLS, seed/embed scripts

The client owns a single optimistic store; the server loads all workspace data once, mutations hit /api/*, and Supabase Realtime reconciles. RLS is enforced in Postgres, but because the app's Drizzle connection bypasses it, every endpoint authorizes ownership manually. A deeper tour lives in CLAUDE.md.

Quick start

Prerequisites: Node ≥ 20, pnpm (corepack enable pnpm), and free Supabase + Cloudflare accounts.

pnpm install
cp .env.example .env        # fill in Supabase URL/keys + DATABASE_URL (transaction pooler, :6543)
pnpm db:migrate             # apply migrations
pnpm db:seed                # seed default workspace + Inbox project
pnpm dev                    # → http://localhost:5173

Run pnpm check (type-check + svelte-check across every package) before committing. See .env.example for every variable; a single repo-root .env serves both the web app and DB tooling.

Deployment

Both apps deploy as Cloudflare Workers; Supabase hosts the database.

# authenticate once
pnpm --filter @junto/web exec wrangler login

# web app — set secrets, then deploy
pnpm --filter @junto/web exec wrangler secret put DATABASE_URL
pnpm --filter @junto/web exec wrangler secret put SUPABASE_URL
pnpm --filter @junto/web exec wrangler secret put SUPABASE_SERVICE_ROLE_KEY
pnpm --filter @junto/web exec wrangler secret put PUBLIC_SUPABASE_URL
pnpm --filter @junto/web exec wrangler secret put PUBLIC_SUPABASE_ANON_KEY
pnpm build && pnpm --filter @junto/web exec wrangler deploy

# MCP server — set secrets, then deploy (also registers the keep-alive cron)
pnpm --filter @junto/mcp exec wrangler secret put DATABASE_URL
pnpm --filter @junto/mcp exec wrangler secret put MCP_BEARER_TOKEN   # e.g. `openssl rand -hex 32`
pnpm mcp:deploy

Keep-alive (free-tier Supabase). Free projects pause after ~a week idle. Two guards, use either: the MCP Worker's daily Cron Trigger (select 1, comes with pnpm mcp:deploy), or a GitHub Actions workflow at .github/workflows/keepalive.yml (add SUPABASE_URL + SUPABASE_ANON_KEY repo secrets — no deploy needed).

MCP — connect Claude & Cursor

The apps/mcp Worker speaks the Model Context Protocol over Streamable HTTP at POST /mcp, authenticated by a single bearer token. Tools: list_projects, list_tasks, create_task, update_task, create_project. The in-app MCP tab generates ready-to-paste config.

Cursor~/.cursor/mcp.json:

{
  "mcpServers": {
    "junto": {
      "url": "https://<your-worker>.workers.dev/mcp",
      "headers": { "Authorization": "Bearer YOUR_MCP_BEARER_TOKEN" }
    }
  }
}

Claude Desktopclaude_desktop_config.json (via mcp-remote, which bridges the remote server + bearer header):

{
  "mcpServers": {
    "junto": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://<your-worker>.workers.dev/mcp",
               "--header", "Authorization: Bearer YOUR_MCP_BEARER_TOKEN"]
    }
  }
}

Search

GET /api/search powers the ⌘K palette. Full-text search (a Postgres tsvector + GIN index) works everywhere. Semantic search uses pgvector + a local Ollama (nomic-embed-text); run pnpm db:embed to backfill, and it transparently falls back to FTS where Ollama isn't reachable (e.g. the deployed edge).

Scripts

Command Description
pnpm dev Web dev server
pnpm build Production build (Cloudflare adapter)
pnpm check Type-check every workspace
pnpm db:migrate Apply pending migrations
pnpm db:seed Seed default user/workspace/project
pnpm db:embed Backfill task embeddings via local Ollama
pnpm mcp:dev Run the MCP Worker locally
pnpm mcp:deploy Deploy the MCP Worker (+ keep-alive cron)

License

AGPL-3.0 © Aayush Charde

Junto is licensed under the GNU Affero General Public License v3.0. It's fully open-source — and because the AGPL's network clause (section 13) applies, anyone who runs a modified version as a hosted/network service must also make their modified source available to that service's users.

About

Keyboard-first task tracker with a built-in MCP server — manage your tasks from Claude or any MCP client. SvelteKit · Cloudflare Workers · Supabase · pgvector. AGPL-3.0.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages