λx.xDocs← app

Contributing

Vinculum is MIT-licensed. Contributions are welcome — here's how to set up and how we work.

Code of conduct

We follow the Contributor Covenant 2.1. Short version: be decent, no harassment, assume good faith. If something feels off, email the maintainers.

Dev setup

1

Clone the repo

bash
git clone https://github.com/whalefall-media/vinculum.git cd vinculum
2

Install Python backend (editable)

bash
uv pip install -e '.[dev]'

The -e flag is required

Without editable install, git pullupdates won't reach the running server. This has caused production outages. Always use -e.

3

Start a local Postgres

bash
docker run -d \
  --name vinculum-pg \
  -e POSTGRES_USER=vinculum_app \
  -e POSTGRES_PASSWORD=dev \
  -e POSTGRES_DB=vinculum \
  -p 5432:5432 \
  pgvector/pgvector:pg17
4

Configure and migrate

bash
cp env.example .env
# Edit .env — set VINCULUM_DATABASE_URL:
# VINCULUM_DATABASE_URL=postgresql://vinculum_app:dev@localhost:5432/vinculum

vinculum-mcp migrate
5

Start the backend

bash
vinculum-mcp run   # MCP server + REST API on :31415
6

Start the frontend

bash
cd frontend
pnpm install
pnpm dev   # dev server on :5175, proxies /api → :31415
7

Install spawn daemon (optional)

Only needed if you're working on grunt spawning:

bash
export VINCULUM_DATABASE_URL="postgresql://vinculum_app:dev@localhost:5432/vinculum"
./hooks/install-spawnd.sh

PR workflow

Vinculum uses its own tooling to track contributions. The workflow is a condensed version of how the maintainers work internally — you're using the product to improve the product.

1. File a directive

Write a directive entry in your local Vinculum instance describing what you want to change and why. Use the write MCP tool with entry_type=handoff:

text
entry_type: handoff
branch: platform   # or whichever branch fits
content: |
  # DIRECTIVE: <short title>

  <What to change and why. Acceptance criteria.>

2. Implement it

Make your changes. When done, write an implementation entry:

text
entry_type: implementation
metadata.replies_to_directive: <directive_id>
metadata.files_touched: [list of changed files]
content: |
  # IMPLEMENTATION — <title>

  What was done, any decisions made during implementation.

3. Open a PR

Open a PR on GitHub (or Forgejo if self-hosted) with a link to the implementation entry in the body:

text
Vinculum implementation entry: #<id>

Maintainers review both the entry and the diff. The directive captures the intent; the implementation entry captures decisions made during execution.

Why this workflow?

It mirrors how Vinculum actually operates. Running Vinculum to contribute to Vinculum is the fastest way to find sharp edges — you're a user of the thing you're improving. And the directive preserves the “why” that no PR description fully captures.

Testing

Backend

bash
# Set a test database URL (separate DB from dev)
export VINCULUM_TEST_DATABASE_URL="postgresql://vinculum_app:dev@localhost:5432/vinculum_test"

# Create test DB and run migrations
createdb -U vinculum_app vinculum_test
vinculum-mcp migrate

# Run tests
pytest tests/ -v

No mocks

Tests hit a real database. Mock-based testing has caused outages when the mock/prod schema diverged. This is non-negotiable.

Frontend

bash
cd frontend
pnpm typecheck   # TypeScript strict mode
pnpm lint        # eslint-config-next

MCP smoke test

Connect Claude Code to your local instance, then manually verify:

  1. Call write with a test entry — verify it appears in the dashboard at http://localhost:31415/dashboard
  2. Call searchfor the entry's content — verify full-text indexing
  3. If VINCULUM_VOYAGE_API_KEY is set, verify semantic search returns related entries
  4. Try spawn_grunt with a simple test directive — verify the grunt session appears in the Sessions panel

Style

The full convention set is auto-rendered at Conventions. Quick summary:

Python

bash
ruff format .
ruff check .

# Or install the pre-commit hook:
pre-commit install

TypeScript

bash
pnpm lint
pnpm typecheck

Comments

Comment why, not what. No multi-line docstrings explaining what a function does when the name says it. A comment that would confuse no future reader is a comment that shouldn't exist.

No-mock policy

Don't mock the database in tests. The mock/prod divergence has caused real outages.

Where to start

  • Issues tagged good-first-issue on GitHub
  • metadata.priority=informationaldirectives in the open substrate — these are specced features that haven't been claimed yet
  • The factory branch in the substrate tracks infrastructure and tooling improvements
  • The /docs site itself — documentation gaps are the highest-return contribution for new contributors who are still learning the codebase

If you're unsure whether something is worth contributing, open an issue first. The fastest path is to file a recon entry in the substrate and link it in the issue — that's what the maintainers do internally.