GitHub Actions
Hooks cover the machines you control. A CI check covers everyone: every pull request is searched against the decision record, and matching decisions are posted on the PR.
1. Create a read-only grant
Follow the one-time token setup on the Hooks page with two changes: name the client precedent-ci and keep the scope to decisions:read. CI never needs to draft. The grant acts as the person who approved it and is listed under Settings, Agents, where it can be revoked.
2. Store the secrets
PRECEDENT_URL: your deployment, for example https://app.example.comPRECEDENT_CLIENT_ID: from the registration stepPRECEDENT_REFRESH_TOKEN: from the token exchangePRECEDENT_ROTATE_PAT: a fine-grained GitHub token with Secrets write access on this repository, used to store the rotated refresh token after each run
3. Add the workflow
Save as .github/workflows/precedent.yml:
name: precedent
on: pull_request
concurrency: precedent-check # rotation-safe: one run at a time
permissions:
pull-requests: write
contents: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Search the decision record with this diff
env:
BASE: ${{ secrets.PRECEDENT_URL }}
CLIENT_ID: ${{ secrets.PRECEDENT_CLIENT_ID }}
REFRESH: ${{ secrets.PRECEDENT_REFRESH_TOKEN }}
GH_TOKEN: ${{ github.token }}
ROTATE_TOKEN: ${{ secrets.PRECEDENT_ROTATE_PAT }}
run: |
SUMMARY=$(git log --format=%s origin/${{ github.base_ref }}..HEAD | head -5
git diff --stat origin/${{ github.base_ref }}...HEAD | tail -15)
FRESH=$(curl -sf "$BASE/api/oauth/token" -d grant_type=refresh_token \
-d refresh_token="$REFRESH" -d client_id="$CLIENT_ID")
# Rotation: store the new refresh token before doing anything else.
echo "$FRESH" | jq -r .refresh_token \
| GH_TOKEN="$ROTATE_TOKEN" gh secret set PRECEDENT_REFRESH_TOKEN --repo "${{ github.repository }}"
ACCESS=$(echo "$FRESH" | jq -r .access_token)
BODY=$(jq -n --arg q "$SUMMARY" \
'{jsonrpc:"2.0", id:1, method:"tools/call",
params:{name:"search_decisions", arguments:{query:$q, limit:5}}}')
HITS=$(curl -sf "$BASE/mcp" \
-H "Authorization: Bearer $ACCESS" -H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" -H "MCP-Protocol-Version: 2025-06-18" \
-d "$BODY" \
| jq -r '.result.structuredContent.decisions[]?
| select(.status == "decided")
| "- [\(.ref) \(.title)](\(.url))"')
if [ -n "$HITS" ]; then
gh pr comment ${{ github.event.number }} --body "$(printf \
'This change touches decided topics. Cite them in the PR, or open a supersession:\n\n%s' "$HITS")"
fiComment or fail?
The workflow above comments and lets the merge proceed, which is the right starting point: hybrid search surfaces decisions that are related, and a human or the reviewing agent judges whether the change actually conflicts. Once the comments have earned trust, make it blocking by replacing the comment step with exit 1 and marking the job required in branch protection. Teams that want the judgement automated too can have their review agent read the comment; its verdict cites the decision either way.