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
Clone the repo
git clone https://github.com/whalefall-media/vinculum.git cd vinculumInstall Python backend (editable)
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.
Start a local Postgres
docker run -d \
--name vinculum-pg \
-e POSTGRES_USER=vinculum_app \
-e POSTGRES_PASSWORD=dev \
-e POSTGRES_DB=vinculum \
-p 5432:5432 \
pgvector/pgvector:pg17Configure and migrate
cp env.example .env
# Edit .env — set VINCULUM_DATABASE_URL:
# VINCULUM_DATABASE_URL=postgresql://vinculum_app:dev@localhost:5432/vinculum
vinculum-mcp migrateStart the backend
vinculum-mcp run # MCP server + REST API on :31415Start the frontend
cd frontend
pnpm install
pnpm dev # dev server on :5175, proxies /api → :31415Install spawn daemon (optional)
Only needed if you're working on grunt spawning:
export VINCULUM_DATABASE_URL="postgresql://vinculum_app:dev@localhost:5432/vinculum"
./hooks/install-spawnd.shPR 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:
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:
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:
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
# 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/ -vNo mocks
Tests hit a real database. Mock-based testing has caused outages when the mock/prod schema diverged. This is non-negotiable.
Frontend
cd frontend
pnpm typecheck # TypeScript strict mode
pnpm lint # eslint-config-nextMCP smoke test
Connect Claude Code to your local instance, then manually verify:
- Call
writewith a test entry — verify it appears in the dashboard athttp://localhost:31415/dashboard - Call
searchfor the entry's content — verify full-text indexing - If
VINCULUM_VOYAGE_API_KEYis set, verify semantic search returns related entries - Try
spawn_gruntwith 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
ruff format .
ruff check .
# Or install the pre-commit hook:
pre-commit installTypeScript
pnpm lint
pnpm typecheckComments
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-issueon GitHub metadata.priority=informationaldirectives in the open substrate — these are specced features that haven't been claimed yet- The
factorybranch in the substrate tracks infrastructure and tooling improvements - The
/docssite 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.