Contributing
How to set up a local development environment, run the test suites, and submit a pull request to Stash.
Prerequisites
Local development setup
# 1. Clone
git clone https://github.com/Fergana-Labs/stash.git
cd stash
# 2. Start Postgres
docker compose up -d postgres
# 3. Backend dependencies (includes test tooling)
pip install -r backend/requirements-dev.txt
# 4. Configure environment
cp .env.example .env
# Embeddings default to local sentence-transformers — no key needed.
# Set OPENAI_API_KEY or HF_TOKEN to use a hosted embedding provider instead.
# 5. Apply database migrations
python -m alembic upgrade head
# 6. Frontend dependencies
cd frontend && npm ci && cd ..
# 7. Start both services
./start.sh
# Backend → http://localhost:3456
# Frontend → http://localhost:3457Running tests
Both suites must pass before a PR can be merged.
# Backend — create a separate test database
psql postgresql://stash:stash@localhost:5432/postgres -c "CREATE DATABASE stash_test;"
# Run migrations against the test DB
DATABASE_URL=postgresql://stash:stash@localhost:5432/stash_test \
python -m alembic upgrade head
# Run the full test suite
DATABASE_URL=postgresql://stash:stash@localhost:5432/stash_test \
TEST_DATABASE_URL=postgresql://stash:stash@localhost:5432/stash_test \
python -m pytest backend/tests/ -v
# Frontend
cd frontend && npm testMaking changes
Keep pull requests focused on a single logical change.
Add or update tests for any behaviour you change. The minimum coverage threshold is enforced by CI.
Create an Alembic migration (python -m alembic revision -m "description"). Write both upgrade() and downgrade() using op.execute() with raw SQL.
All queries must use parameterised placeholders ($1, $2, …). No string interpolation in SQL.
PEP 8, type annotations on all public functions.
ESLint with eslint-config-next. Run npm run lint before pushing.
Explain why, not what. Avoid narrating obvious code.
Submitting a pull request
Fork the repository and create a feature branch off main.
Ensure both test suites pass locally.
Open a PR against main. The CI pipeline runs both suites automatically.
Describe the motivation for the change in the PR body. Link any related issues.
A maintainer will review and merge once CI is green.
Adding a schema change
# 1. Create a new migration
python -m alembic revision -m "add_my_column"
# 2. Edit backend/migrations/versions/<hash>_add_my_column.py
# Write both upgrade() and downgrade() using op.execute() with raw SQL.
# 3. Apply and verify locally
python -m alembic upgrade head
# 4. Add a migration test if there is non-trivial data logic
# → backend/tests/test_migrations.py