# Parabol runs agile retros, sprint poker and pulse surveys on your own Postgres

> Parabol is a self-hosted meeting server for agile teams, with retrospectives, sprint poker and anonymous team health checks sharing one GraphQL backend, one Kanban board and one Postgres database. The air-gapped pitch holds up, but the shipped defaults pull in two local AI model ports, a 16 GB Docker floor and a repository file that disagrees with package.json.

**ParabolInc/parabol** — Free online agile retrospective meeting tool

- Repository: https://github.com/ParabolInc/parabol
- Website: https://www.parabol.co/
- Stars: 2,017 · Forks: 372
- Language: TypeScript
- License: NOASSERTION
- Published: 2026-10-13 · Updated: 2026-10-13 · Language: en
- Canonical page: https://hysenlabs.com/projects/parabolinc-parabol

## Retrospectives move through reflect, group, vote, discuss, action

Parabol is a meeting server rather than a board with a voting widget bolted on. A retrospective walks a fixed pipeline of reflect, group, vote, discuss, action, and the grouping stage is where it does its real work: raw reflections are merged into themes before any counting starts, so votes land on themes rather than on individual sentences. Templates cover Start/Stop/Continue, 4Ls and Mad/Sad/Glad, and custom templates are supported.

Four more meeting types share those same objects. Sprint Poker estimates with Fibonacci, T-shirt or custom scales and is built for asynchronous play rather than one synchronous call. Check-In Meetings, named Action, run an agenda with icebreakers, task review and action items. Standup, named Team Prompt, is written rather than spoken and can recur on a schedule. Pages are Yjs backed documents scoped to a team or a personal workspace, and they attach to the meeting that produced them.

Everything lands on one Kanban board with four columns, active, stuck, done and future. A task raised in a retro and a task raised in a check-in occupy the same board, and summaries with their action items are captured by the meeting itself instead of being retyped into a tracker.

## Air-gapped hosting bundles Postgres, Valkey and a pm2 process manager

Three services make up a production install: Node.js as the server, PostgreSQL for storage, and Valkey for pubsub and cache. Live traffic runs over graphql-ws WebSockets served by μWebSockets.js, with Relay holding the client cache and React plus Tailwind CSS on top.

The process manager is pm2, and the repository ships two configurations for it. Production starts through `pm2-runtime start pm2.config.js`, while development hands `pm2 start pm2.dev.config.js --no-daemon` to pm2 after sourcing .env, with `PM2_SILENT=true` set. A predev script kills leftover processes matching Parabol's own script paths and Relay before restarting, which matters on a laptop that has already run the dev stack several times that morning.

Nodes identify themselves with `SERVER_ID`, documented as cluster node number 0 to 1023 and required to be unique per process. That one key is what lets several Parabol processes share a Valkey instance without their subscriptions colliding. Two further env keys shape what sits in front of the server: `PROTO` defaults to https, and `TRUSTED_PROXY_COUNT`, when set, must match the number of proxies in the stack or rate limiting can reject all traffic arriving through the proxy.

## Cloning, pnpm install and a Docker Compose database on port 3000

The install path is five commands, and it assumes Node.js and pnpm are already on the host. Production also wants PostgreSQL and Valkey reachable. The development path reaches them through Docker Compose, and Watchman appears in the development prerequisites for file watching.

```bash
git clone https://github.com/ParabolInc/parabol.git
cd parabol
cp .env.example .env   # add your own vars
pnpm i
pnpm db:start
pnpm dev
```

`pnpm db:start` does not start the application. It creates a dev folder and runs docker compose against docker/stacks/development/docker-compose.yml in detached mode, which is how the Postgres and Valkey containers come up before any Parabol code touches a database. `pnpm dev` then exports .env into the shell and hands the process to pm2. Once the stack answers, the app listens on port 3000 over https, and `SOCKET_PORT` is set to 3001 for the development WebSocket server.

The .env file you copy matters as much as the commands. `HOST` is localhost, `PORT` is 3000, and `SERVER_SECRET` ships as key_SERVER_SECRET, a placeholder value you have to replace before anything else. Two org flags interact rather than stand alone: `IS_SINGLE_ORG` only takes effect once `IS_ENTERPRISE` is true, since the sample file gates the creation of new orgs on both.

## pm2 runs both modes, and clean deletes everything untracked

The root package.json covers the whole lifecycle, from the dev loop to a production start:

```json
  "build": "node --max-old-space-size=8192 scripts/prod.js",
  "clean": "git clean -fdx -e .env",
  "codegen": "node scripts/codegenGraphQL.js",
  "pg:restore": "node ./scripts/toolbox/pgRestore.js",
  "db:start": "mkdir -p dev && docker compose -f docker/stacks/development/docker-compose.yml up -d"
```

Four details stand out. The build raises the Node heap ceiling to 8192 MB, so a smaller box fails the build rather than the app. `pg:generate` assembles a postgres URL from POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST, POSTGRES_PORT and POSTGRES_DB, writes the result to ./packages/server/postgres/types/pg.d.ts and runs `biome check --write` over it, so checked-in database types are expected to match your own schema. `pg:restore` is a single node call into scripts/toolbox/pgRestore.js, and nothing in the root documentation says where it restores from or how to point it at a backup file.

`git clean -fdx -e .env` is the sharpest edge in that block. The flags delete every untracked and ignored path in the tree, and the exclusion is the only thing keeping your keys file out of the sweep, with no dry run wired to it. The last push on the default branch, master, landed on 2026-10-06.

## package.json and the repository file disagree on reuse terms

Repository metadata calls the licence Other, a custom one GitHub cannot classify, and points at the LICENSE file, yet package.json declares AGPL-3.0 in its own license field and the tree carries both LICENSE and COPYING. Anyone assembling a compliance checklist has to resolve that gap against the real file rather than either label.

Two other fields surprise readers who take the open source framing at face value. The package name is `parabol-action`, not parabol, and `private` is set to true, so nothing publishes to a registry under that name. `engines` pins node at ^24.19.0 while the install prerequisites ask only for Node.js, which leaves the version gap unstated until an install fails on a host running an older LTS.

The stack is written in TypeScript, split across a packages/ directory, with a pnpm workspace file, biome for linting, relay.config.js for the client compiler and codegen.json for GraphQL operations. A monorepo of that shape is a real maintenance cost: an upgrade touches the workspace lockfile, the generated types and the Relay artifacts together, and nothing in the root documentation describes a rollback path if the upgrade lands badly.

## Team Health anonymity rides on two local AI model ports

Anonymity in the Team Health check is partly mechanical and partly computational. Answers stay hidden until the check closes, small response sets are never attributed to a person, and comments can be AI-paraphrased so writing style cannot identify the author. That last feature needs a text generation model, and .env.example points both model settings at services you run yourself:

```bash
AI_EMBEDDING_MODELS='[{"model": "text-embeddings-inference:Svenni551/Qwen3-Embedding-0.6B-ONNX-INT8", "url": "http://localhost:3040/", "maxTokens": 4096}]'
AI_GENERATION_MODELS='[{"model": "text-generation-inference:TheBloke/zephyr-7b-beta", "url": "http://localhost:3050/", "maxTokens": 4096}]'
AI_EMBEDDER_WORKERS='1'
```

The default generation model is TheBloke/zephyr-7b-beta served from localhost:3050 with a 4096 token ceiling, and the default embedding model is an ONNX INT8 build of Qwen3-Embedding-0.6B on localhost:3040 with the same ceiling. `AI_EMBEDDER_WORKERS` is set to 1, so a single worker serialises embedding work until you raise it.

Here is the tension worth knowing before you size a host. Air-gapped operation is promoted as needing no external dependencies, and the same page warns that text-embedding-inference is resource intensive enough that Docker's memory limit may need to reach 16 GB or more. Both statements describe the same component, so 16 GB is a floor for the default dev stack rather than a ceiling, and the paraphrasing that protects comment anonymity does not work at all until you serve port 3050 yourself.

## A public GraphQL endpoint and llms.txt for scripted work

Automation runs through GraphQL rather than a REST surface. The hosted deployment publishes an endpoint at https://action.parabol.co/graphql, the schema SDL at https://action.parabol.co/graphql/schema.graphql, and the same endpoint serves a GraphiQL explorer in the browser, so you can read the schema before writing a query.

The tree also ships two plain text references at its root for tooling and for language models: `llms.txt`, a concise overview covering auth, scopes and key operations, and `llms-full.txt`, which carries example GraphQL queries and mutations. Beside them sit graphql.config.js and codegen.json, so the schema, the client codegen configuration and the readable references come out of one repository. `node scripts/codegenGraphQL.js` regenerates typed operations, and Relay reads codegen.json at build time.

What is not documented is as telling. No deprecation window or API version scheme appears in the root files, and the endpoint above belongs to Parabol's own deployment rather than a neutral sandbox, so treat that URL as a specification you can point your own install at. On an isolated network the SDL file and the two text references are what you can carry in, because the hosted endpoint is out of reach and only a self-hosted instance can execute the mutations.

## Nine integrations and the vendors Parabol sets out to replace

The integration list covers nine services. Jira Cloud and Jira Data Center (Jira Server) can import a backlog, push estimates and create issues; GitHub, GitLab, Linear and Azure DevOps import issues and push estimates; Slack and Mattermost carry meeting notifications, with Slack also sharing topics. Google Calendar creates an event when a meeting starts, and Microsoft / Azure AD handles SSO login.

The competitive claim runs in two directions. Against documentation tools, Pages is pitched as a Confluence replacement for teams that want notes and decisions stored beside the meeting that produced them, on infrastructure they run, with Yjs handling the collaborative editing. Against engagement vendors, the Team Health check names Officevibe, Culture Amp, Workday Peakon, 15Five and TeamMood, and argues the difference is where the data lands: a survey that closes into discussion threads and tasks in the same tool, rather than a figure on an HR dashboard.

The measurement side deserves separating from the meeting side. Answers are collected on a 1 to 5 scale against category packs covering Psychological Safety, Dependability, Structure and Clarity, Meaning and Impact, drawn from Google Project Aristotle, Edmondson's Psychological Safety assessment, Lencioni's Five Dysfunctions, Hackman's Team Diagnostic, Gallup Q12, Spotify Squad Health Check, Atlassian Team Health Monitor, Google Project Oxygen and David Rock's SCARF model. You can add questions, define categories or mix packs into a custom template, then run the check weekly, per sprint or monthly, across one team or across the whole organization. Slack and in-app reminders cover participation.

One inconsistency survives all of that: the repository topic tags still list saas and stripe, and the root documentation mentions Stripe nowhere, so anyone reading tags instead of files gets a different picture of the project.

## Conclusion

Parabol fits a team that wants retrospectives, estimation and anonymous pulse surveys running on infrastructure it controls, and the air-gapped claim is the reason people pick it. It is the wrong pick for a group that wants a vendor to run the survey, or for anyone unwilling to operate Postgres, Valkey and pm2. Check three things in .env.example first: whether your host runs the Node version engines demands, whether you will serve the two local AI model ports yourself, and which issue trackers your team actually uses.

## FAQ

### What does Parabol need installed before it runs locally?

Node.js and pnpm are the stated prerequisites. Production also needs PostgreSQL and Valkey, while the development path adds Docker Compose and Watchman, and the dev database is started with pnpm db:start.

### Can Parabol run in an air-gapped network with no internet access?

The project states that it works in air-gapped environments with no external dependencies required, on Node.js, PostgreSQL and Valkey. The shipped .env.example still points AI_EMBEDDING_MODELS at localhost:3040 and AI_GENERATION_MODELS at localhost:3050, so those model services have to run inside your network.

### How does Parabol keep Team Health answers anonymous?

Pulse-survey answers stay hidden until the check closes, small response sets are never attributed to a person, and comments can be AI-paraphrased so writing style cannot reveal the author. Results are then revealed by category and turned into discussion threads and tasks.

### Which issue trackers can Parabol push estimates to?

Jira Cloud and Jira Data Center (Jira Server), GitHub, GitLab, Linear and Azure DevOps all import issues and push estimates. Jira can also create issues and import a backlog.

### Is there a public API for Parabol?

A public GraphQL API is exposed at https://action.parabol.co/graphql, with schema SDL at https://action.parabol.co/graphql/schema.graphql and a GraphiQL explorer in the browser. The repository root also carries llms.txt and llms-full.txt with auth, scopes and example queries.

## Sources

- [Issues](https://github.com/ParabolInc/parabol/issues)
- [ParabolInc/parabol on GitHub](https://github.com/ParabolInc/parabol)
- [Project website](https://www.parabol.co/)
- [README](https://github.com/ParabolInc/parabol/blob/master/README.md)
- [Releases](https://github.com/ParabolInc/parabol/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/parabolinc-parabol
