An ambient AI coworker that lives where you work. Pip is one coworker who shows up in Slack, on your screen, and in your browser. Pip starts with a blank memory and builds your context as you go, or mounts a capability OS you own (like PM OS) if you have one. It's powered by the Cursor CLI, so the same coworker runs on any model.
One coworker. Many surfaces. Your models, your machine, your context — that compounds as you work.
Pip is an open-source harness that brings your AI to where you already work. It takes the coding agent you already trust (via the Cursor CLI), makes it headless, and drops it into Slack, your desktop, and Chrome — one coworker, one shared memory, with the tools to actually ship. The clip below shows a real Slack thread turning into a live roadmap, a meeting moved by voice, and work handed off from any webpage.
▶️ Watch the demo (if the player above doesn't load inline)
Most "AI in your tools" products are a model wrapped in a chat box, locked to one vendor and one surface. Pip flips that:
- The brain is yours, and it compounds. Pip works from day one with zero setup — it saves what
it learns to a local
memory/and reuses it on every surface, so context grows as you work. Bring a capability OS you own (like PM OS — PM skills, domain knowledge, memory) and Pip mounts it as a rich starting point, but nothing is required to begin. - The engine is model-agnostic. Every surface shells out to one shared adapter around
cursor-agent. Switch fromgpt-5tosonnet-4toautowith an env var — no new integration. - The surfaces meet you where you already are. A Slack teammate, a floating desktop task widget, and a browser extension all call the same engine against the same workspace.
┌──────────────────────────────────────────────────────────────────┐
│ SURFACES │
│ Pip · Slack Pip · desktop Pip · Chrome │
│ tag @Pip on-screen page-aware Q&A │
└─────────┬──────────────────────┬──────────────────────┬───────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────┐
│ ENGINE · packages/engine · one adapter around the Cursor CLI │
│ runAgent() → cursor-agent -p … --model <any> --workspace <repo> │
└────────────────────────────────┬───────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────┐
│ BRAIN · external/pm-operating-os (git submodule) │
│ skills · knowledge · memory · MCP tools — loaded via AGENTS.md │
└──────────────────────────────────────────────────────────────────┘
| Surface | Name | What it does | Where |
|---|---|---|---|
| Slack | Pip (@Pip) |
Tag or DM your team's coworker. Runs cursor-agent in the workspace, replies in-thread. |
apps/slack |
| Desktop | Pip | Pip lives on your screen. Click to ask; ⌘⇧T to snip and get an answer. | apps/pip |
| Browser | Pip | Page-aware prompts about whatever tab you're on, via a local bridge to the engine. | apps/chrome-extension |
All three import @tandem/engine. One coworker (Pip) in three places, one brain (PM OS).
curl -fsSL https://raw.githubusercontent.com/Sach1ng/tandem/main/install.sh | bashThat checks Node, grabs the code, builds it, puts the tandem command on your PATH, installs the
Cursor CLI if needed, and initializes your workspace. Then:
cursor-agent login # one-time model auth
tandem pip # launch Pip on your desktopNo PM OS required. Pip starts with a blank memory and builds your context as you go — as you
work, it saves durable facts to ~/.tandem/memory/ and reuses them on every surface. If you do
have a PM OS brain, tandem init picks it up automatically as a rich starting point.
Prerequisites: Node ≥ 20.6 and the Cursor CLI (the installer handles the Cursor CLI for you).
npm install -g @tandem/cli @tandem/pip @tandem/slack
tandem pip # self-initializes ~/.tandem on first run, then launches
tandem doctor # optional: verify Node + cursor-agent
# Slack (after the Pip OAuth app is configured — see apps/slack/README.md)
tandem slack connect # one-click OAuth install into your workspace
tandem slack start # run the coworker bot locallyOptional: use a custom workspace directory:
tandem init ~/my-tandem-workspace
export TANDEM_WORKSPACE=~/my-tandem-workspaceAll surfaces respect TANDEM_WORKSPACE (alias: CURSOR_WORKDIR).
# 1. Clone with the PM OS submodule
git clone --recurse-submodules https://github.com/Sach1ng/tandem.git
cd tandem
# (already cloned? run: git submodule update --init --recursive)
# 2. Install & build
npm install
npm run build
# 3. Verify the engine + inspect the CLI's JSON shape
npm run engine:smokeThen start a surface:
# Slack
cd apps/slack && cp .env.example .env # fill tokens + ALLOWED_USERS
npm start
# Pip (macOS)
npm run pip
# Chrome extension: build it, run the bridge, load dist/ as an unpacked extension
npm run chrome:build
npm run bridge -w @tandem/chrome-extensionPer-surface setup lives in each app's README.
The engine is a thin, well-tested wrapper around cursor-agent:
import { runAgent } from "@tandem/engine";
const { text, chatId } = await runAgent(
{ model: "auto", workspace: repoRoot }, // ← swap models freely
{ prompt, resumeChatId, outputFormat: "json" }, // ← chatId enables thread resume
);Two deliberate design choices, both from hard-won experience:
- No
--system-prompt.cursor-agentdoesn't have one, so persona/charter is delivered via the prepended prompt and the auto-loadedAGENTS.md+.cursor/rules. - Tolerant result parsing. The CLI's JSON shape isn't contractually stable, so
extractResultreads it defensively across versions.npm run engine:smokeshows you exactly what your version emits.
| Single-vendor Slack AI | Pip | |
|---|---|---|
| Models | One vendor's models | Any model the Cursor CLI supports |
| Surfaces | Slack only | Slack + desktop + browser, one shared engine |
| Brain / memory | Closed, hosted | Yours, local, grows as you go (optional PM OS you own) |
| Hosting | Vendor cloud | Your machine, local-first |
| Access | Enterprise-gated | Open source, works solo |
packages/
engine/ Cursor CLI adapter — runAgent, extractResult, resume, smoke test
core/ shared utils — Slack mrkdwn, atomic JSON state, charter loader, workspace resolution
cli/ `tandem` CLI — init, doctor, pip (npm-installable, no git required)
pm-os/ PM OS brain bundle for `tandem init` (npm publish artifact)
apps/
slack/ Bolt coworker (Socket Mode + polling fallback)
pip/ Electron desktop coworker (tasks.md contract, parser, groom/capture)
chrome-extension/ MV3 extension + local bridge server
external/
pm-operating-os/ PM OS — the brain (git submodule for dev; bundled in @tandem/pm-os for install)
AGENTS.md workspace charter, auto-loaded by the engine on every run
From a clean checkout with submodules initialized:
npm run build
npm publish --workspace @tandem/core
npm publish --workspace @tandem/engine
npm publish --workspace @tandem/pm-os
npm publish --workspace @tandem/pip
npm publish --workspace @tandem/clicursor-agent --force lets the agent run shell on your machine — that's how it gets work done, and
it's remote code execution by design. So:
- Always set
ALLOWED_USERSin the Slack app. Empty = anyone in the channel can run commands. - The browser bridge binds to
127.0.0.1only and refuses any request that isn't from the Pip extension: it enforces a loopbackHost(anti DNS-rebind) and checks the browser-set, unforgeableOrigin, so no web page can reach it (blocks bothcorsandno-corsPOSTs). Its/askendpoint runs in read-onlyaskmode; only the explicit Assign to Pip action (/assign) runs with full tool access. Request bodies are capped. - The desktop monitor also binds to
127.0.0.1only, is GET-only, and enforces a loopbackHostcheck. .envand all runtime state (sessions.json,processed.json,open-threads.json) are gitignored.
All four surfaces are live-tested against a local cursor-agent:
npm run verify # 16 offline checks
npm run engine:smoke # CLI + JSON parse
npm run slack:smoke # agent + Slack DM reply
npm run pip:agent-smoke # groom + capture
npm run pip:screenshot-smoke # vision (set TEST_IMG=… if no Screen Recording)Slack setup wizard: npm run slack:setup → http://127.0.0.1:8766
Roadmap: ambient/proactive nudges, scheduled tasks, and more surfaces.
Co-created by Sachin Gupta (@Sach1ng) and Hardik Tiwari (@hardiktiwari).
Stands on PM OS and the Cursor CLI.
Personal project. Not affiliated with or endorsed by any employer or vendor.
MIT — see LICENSE.
