Shoddy · Picker
The download, getting it on PATH, registering it with each client, the local file, and doctor. Read this once per machine.
Most of this page belongs to the tools level, which is the level that is always on. The one exception is the section on burler, a helper program that only the screenings level needs. Where it matters, each section says which level it serves.
Each release has one archive for each operating system, where an archive is one file that holds others, like a zip file. Inside is a single program that needs no .NET runtime on your machine.
| Platform | Archive |
|---|---|
| Windows | pick-X.Y.Z-win-x64.zip |
| macOS, Apple silicon | pick-X.Y.Z-osx-arm64.tar.gz |
| macOS, Intel | pick-X.Y.Z-osx-x64.tar.gz |
| Linux | pick-X.Y.Z-linux-x64.tar.gz |
The macOS and Linux archives are tar files, because only a tar file keeps the mark that lets a program run. Each archive also holds the notice and license files. Two Microsoft libraries are built into the program, and both use the MIT license. ScriptDom reads T-SQL, the SQL that SQL Server speaks, and the query gate is built on it. SqlClient carries the connection to the server.
pick and in no other program here. In the same way, PdfPig is only in fettle, and ONNX Runtime is only in burler, because no program here uses another's code. The full list of libraries is in THIRD-PARTY-NOTICES.md.PATHPATH is the list of folders where your system looks for the commands you type. The commands below unpack pick into a folder of its own and add that folder to the list.
$dir = "$env:LOCALAPPDATA\Programs\pick"
New-Item -ItemType Directory -Force $dir | Out-Null
Expand-Archive pick-X.Y.Z-win-x64.zip -DestinationPath $dir -Force
Get-ChildItem $dir -Recurse | Unblock-File
$user = [Environment]::GetEnvironmentVariable('Path', 'User')
if ($user -notlike "*$dir*") {
[Environment]::SetEnvironmentVariable('Path', "$user;$dir", 'User')
}mkdir -p ~/.local/bin
tar -xzf pick-X.Y.Z-osx-arm64.tar.gz -C ~/.local/bin
xattr -d com.apple.quarantine ~/.local/bin/pick # macOS onlyThen open a new terminal and check that pick runs:
pick versionThree problems give no error message of their own. If the check fails, look at each of them in turn.
PATH only once, when it starts, so open a new one before you decide the change did not work.Unblock-File line in the commands removes the mark.xattr line in the commands removes that mark.You can also build pick yourself from this repository. No other project here has to be built first, because pick uses none of them:
./scripts/fettler-build.ps1 publish X.Y.Z # makes the fettle, burler and pick archivesThe archives land in the artifacts/publish/ folder. To build only pick, and only for this machine, run this instead:
dotnet publish pick -c Release -r win-x64 --self-contained `
-p:PublishSingleFile=true -o $env:LOCALAPPDATA\Programs\pickpick moves its network traffic the same way on Windows, macOS and Linux. Older SQL Server drivers used a network part that only Windows has. pick turns that part off twice: once in its settings file, and once in the first line of code it runs. No archive carries a Windows-only network library, so pick has no behaviour that only Windows shows.
To register pick is to add one entry to a file that your AI client reads, where a client is the program the assistant runs in. pick has no setup command, so you write the entry by hand. The entry holds the same command and arguments in every client, and only the file and the name of the outer key change.
| Client | File | Key |
|---|---|---|
| Claude Code, this project | .mcp.json in the project folder | mcpServers |
| Claude Code, every project | ~/.claude.json | mcpServers |
| Claude Desktop | claude_desktop_config.json in the Claude folder under your app data | mcpServers |
| VS Code with Copilot Chat | .vscode/mcp.json in the project folder | servers |
For Claude Code, the entry in .mcp.json is the one below, and the Claude Code extension for VS Code reads the same file.
{
"mcpServers": {
"picker": { "command": "pick", "args": ["serve"] }
}
}For VS Code with Copilot Chat, the entry in .vscode/mcp.json is this:
{
"servers": {
"picker": { "command": "pick", "args": ["serve"] }
}
}Claude Desktop has no project folder, so it starts pick in a folder of its own, where pick finds no .picker.json. Name the file yourself with --config and its full path:
{
"mcpServers": {
"picker": { "command": "pick", "args": ["serve", "--config", "C:\\github\\app\\.picker.json"] }
}
}No deny list goes with any of these entries. A deny list is a client setting that blocks some of the client's own built-in tools. The clients have no built-in tool for SQL, so pick adds a route to the data without opening any other.
The local file, .picker.local.json, sits beside .picker.json, and you keep it out of source control. It holds what is different on each machine and what must never be checked in. It may supply two things and nothing else:
.picker.json declares, under tools.servers.NAME.connect, where the string may hold a password.screenings.models.{
"tools": { "servers": { "main": { "connect": "Server=(localdb)\\MSSQLLocalDB;Integrated Security=true;TrustServerCertificate=true" } } },
"screenings": { "models": "C:\\screening-models" }
}If the local file names a server that .picker.json does not declare, pick refuses to load. The same happens if it declares databases, a guardrails section or a screen, because the local file cannot widen what the reviewed file allows. pick also refuses a password in .picker.json itself, because that file goes into source control.
The doctor verb checks the setup and prints one line for each check. It opens with the three level lines, so that you see first which levels are on. Then it checks the configuration file and makes a short test connection to each server.
pick 2.1.0
ok tools: on, always; settings from C:\github\app\.picker.json
ok guardrails: off
ok screenings: off
ok configuration: C:\github\app\.picker.json
ok server main: connects (guardrails off: every database the login can reach)A check that failed starts with !! in place of ok. A level that is off gets one line, and doctor runs none of that level's checks. So the models and burler lines appear only when screenings are on. It never prints a connection string or a password.
Skip this section unless you turn on screenings. The first tier of the screen runs inside pick with nothing else installed. Three categories, clinical, legal and scientific, need models, and the models run in burler, a helper program. The fettle program uses the same helper, so one download serves both of them.
PATH, so if it already sits beside fettle, copy the same file.pick doctor to check both. With screenings on, it reports the models folder and whether the helper is in place.The command pick serve starts pick as an MCP server. MCP is the protocol (a set of rules for messages) that AI clients use to call outside tools. The client starts the server, and you do not. If you run it by hand, it waits for input and looks stuck, which is normal.
The tools are named mcp__picker__VERB, such as mcp__picker__catalogs. Each answer is the same one that the command line gives when you add --json.
pick VERB | pick serve | |
|---|---|---|
| Started by | you, or a script | the client, from the entry above |
| Reads its settings from | the nearest .picker.json at or above the current folder, or --config PATH | the .picker.json where the client started it, or --config PATH. It reads the file again before every call. |
| Answers with | text, or JSON with --json | MCP results, the same as --json |
No tool takes a connection string, a server name or a database name, so the assistant cannot point pick anywhere new. You edit the two files, and pick refuses to write them. The instructions that pick sends the client at startup say which levels are on.
catalogs. If the tool is missing, the server did not start, and the usual cause is that pick is not on PATH..picker.json needs no restart.PATH entry, then remove the "picker" entry from each client file that names it. The two .picker files in a project are yours to keep or delete, and pick wrote nothing anywhere else.