Introducing siftwise · Part 6 of 10
Try it
You need Docker, git and uv. The commands are bash; on Windows, use Git Bash or WSL. The quickstart takes about five minutes, and the project's CI runs it on every change.
Install the CLI
pip install siftwise # the light CLI: select, record, triage, report, rollup
pip install 'siftwise[server]' # plus the API server
pip install 'siftwise[mcp]' # plus siftwise mcp, for coding agentsStart the server (Docker Compose)
The compose file runs the published image,
ghcr.io/pramodbasavarajmenasi/siftwise:0.1.0, with Postgres 16. The API token is a
shared secret you choose; it goes in .env:
git clone https://github.com/PramodBasavarajMenasi/siftwise.git
cd siftwise
[ -f .env ] || echo "SIFTWISE_API_TOKEN=$(openssl rand -hex 32)" > .env
docker compose up -d --wait # pulls the image, waits until both services are healthy
curl -fsS http://localhost:8000/healthz # {"status":"ok"}
uv tool install siftwise # or: pip install siftwise
export SIFTWISE_API_TOKEN=$(sed -n 's/^SIFTWISE_API_TOKEN=//p' .env)Without compose, run the image directly against your own Postgres:
docker run -d -p 8000:8000 -e SIFTWISE_API_TOKEN=... \
-e SIFTWISE_DATABASE_URL=postgresql+psycopg://user:password@db-host:5432/siftwise \
ghcr.io/pramodbasavarajmenasi/siftwise:0.1.0Record a run, then select
The repo ships a small example project. Record its tests once, change a file, and ask what to run:
demo="$(mktemp -d)/shop" && cp -r examples/quickstart "$demo" && cd "$demo"
git init -q && git add -A && git commit -qm "A shop"
uv run pytest -q --junitxml=junit.xml
siftwise record junit.xml --repo demo/shop --branch main --main
echo "# reviewed the bulk discount" >> shop/cart.py && git commit -qam "Touch the cart"
siftwise select --repo demo/shop --base HEAD~1 > selected.sh
cat selected.sh # pytest tests/test_cart.py
uv run sh selected.shThe command goes to stdout and a summary to stderr:
siftwise: python imports: 1 test file(s) import changed modules
siftwise: selective (2 of 4 known tests): 2 of 4 known tests selected--json adds a reason per test; docker compose down stops the
server.
The GitHub Action
Add two secrets, SIFTWISE_URL and SIFTWISE_TOKEN, and check out with
fetch-depth: 0 so the base...head diff works. For a matrix, each leg
selects and records its own variant, and one rollup job runs after every leg:
name: CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
actions: read
pull-requests: write
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
python: ["3.11", "3.12"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python }}
- run: pip install -r requirements.txt # your install step
- id: siftwise
uses: PramodBasavarajMenasi/siftwise/actions/select@main
with:
server-url: ${{ secrets.SIFTWISE_URL }}
token: ${{ secrets.SIFTWISE_TOKEN }}
comment: ${{ strategy.job-index == 0 }} # one leg comments, or they race
- name: Tests
env:
MODE: ${{ steps.siftwise.outputs.mode }}
COMMAND: ${{ steps.siftwise.outputs.command }}
JUNIT_DIR: ${{ steps.siftwise.outputs.junit-dir }}
run: |
if [ "$MODE" = selective ]; then
# Shell-quoted by siftwise; each pytest command writes its own report to JUNIT_DIR.
if [ -n "$COMMAND" ]; then eval "$COMMAND"; else echo "No tests affected."; fi
else
pytest --junitxml="$JUNIT_DIR/full.xml" # your normal full suite
fi
- if: always()
uses: PramodBasavarajMenasi/siftwise/actions/record@main
with:
server-url: ${{ secrets.SIFTWISE_URL }}
token: ${{ secrets.SIFTWISE_TOKEN }}
variant: ${{ matrix.os }}-py${{ matrix.python }}
siftwise-rollup:
needs: test
if: always()
runs-on: ubuntu-latest
steps:
- uses: PramodBasavarajMenasi/siftwise/actions/rollup@main
with:
server-url: ${{ secrets.SIFTWISE_URL }}
token: ${{ secrets.SIFTWISE_TOKEN }}Never use these actions with pull_request_target, which runs a fork's code with
your secrets; use pull_request. Pin @v0.1.0 or a commit SHA instead
of @main for reproducible CI. In a single job, leave out the rollup job:
record triages on its own.
MCP for coding agents (tested with Claude Code)
Install the CLI with the mcp extra, then register it. The agent starts the MCP
server in its working directory, so open the agent in the repository:
uv tool install 'siftwise[mcp]' # or: pip install 'siftwise[mcp]'
claude mcp add siftwise --env SIFTWISE_SERVER=https://siftwise.example.com \
--env SIFTWISE_API_TOKEN=your-token -- siftwise mcpOr commit a project .mcp.json, which expands ${VAR} from your
environment, so the token itself stays out of the repo:
{
"mcpServers": {
"siftwise": {
"command": "siftwise",
"args": ["mcp"],
"env": {
"SIFTWISE_SERVER": "https://siftwise.example.com",
"SIFTWISE_API_TOKEN": "${SIFTWISE_API_TOKEN}"
}
}
}
}Then tell the agent when to use it, in CLAUDE.md or AGENTS.md:
Before running tests, call the siftwise `select_tests` tool and run the command it returns.
When tests fail, call `triage_failure` before fixing anything: fix `new_regression` failures,
re-run `flaky` ones, and leave `pre_existing` ones (already failing on main).The README also has configs for Codex and Cursor (untested so far; Claude Code is the tested client).