CHAIN detects breaking REST API changes across repositories, walks every downstream dependency—including BFF/proxy hops—and alerts the specific Slack owners before their feature breaks.
When one API contract changes, every linked team should know before production does.
Built for OpenAI Build Week's Developer Tools track with Python, FastAPI, OpenAI GPT-5.6, and three runnable Node.js demo services.
Try the live interactive demo — use the access code included in the Devpost submission. No installation is needed.
Codex was the development partner from the initial PRD to the deployed judge experience. In one continuous build workflow, it helped turn the idea into the graph model, implement the JS/TS static analyzer and incremental store, connect the GitHub webhook and Slack delivery pipeline, create the three-repository fixture, build the visual demo, prepare Vercel deployment, and add and run the 23-test suite. Codex also accelerated the less visible work that normally slows down a prototype: tracing cross-repository evidence loss, fixing the BFF's dual role as both API provider and caller, validating real Slack delivery, and checking the hosted experience end to end.
The key product and architecture decisions remained explicit human choices:
- Model dependencies as a directed graph and traverse it in reverse so a single upstream change exposes every downstream feature and owner.
- Preserve caller-owned edges during incremental scans; rescanning the changed provider must not erase dependency evidence discovered in other repos.
- Keep deterministic static analysis on the common path and invoke GPT-5.6 only at semantic boundaries where rules are brittle.
- Notify affected owners with endpoint, feature, path, and hop distance instead of broadcasting a generic repository-change alert.
- Give judges a guarded, browser-based scenario that demonstrates both a real alert and a zero-notification safe change without requiring a local build.
GPT-5.6 is part of the running product, not just the build process. Through the OpenAI Responses API and strict structured output, it performs two focused judgment tasks:
- Breaking-change classification: distinguish an external REST contract change from an internal refactor or comment-only edit and return the affected method, path, change type, and rationale.
- Ambiguous dependency resolution: match uncertain env-driven HTTP calls to known endpoints with an explicit confidence score.
This hybrid keeps CHAIN fast, inspectable, and cost-conscious while using GPT-5.6 precisely where semantic understanding improves the result. The hosted demo exposes the model provider and rationale so judges can verify that path directly.
employee-app ("My HR Info")
└─ GET /api/hr-info
employee-app-server (BFF)
└─ GET /api/employee/profile
hrm-server
hrm-server changes GET /api/employee/profile from the legacy
x-session-token contract to required Bearer authentication. It does not know
who calls it. CHAIN identifies both the BFF (one hop) and employee app (two hops),
then produces a targeted alert for @mina-app naming the "My HR Info" feature.
- Static JS/TS analysis for Express routes,
fetch, andaxioscalls. - Base URL resolution through constants and
process.env.* || <fallback>values. - Server-handler analysis, so one repo can expose an endpoint and call another.
- GPT-5.6 structured-output fallback for ambiguous edge matching.
- JSON graph persistence with repo-scoped incremental replacement.
- Unbounded reverse graph traversal with shortest-hop deduplication.
- GPT-5.6 structured diff classification with a deterministic offline fallback.
- GitHub push webhook handling, HMAC SHA-256 verification, and Compare API diffs.
- Slack Incoming Webhook alerts with owner, chain, endpoint, and feature.
- A no-credential demo harness, interactive judge site, graph visualization, and 23 automated tests.
The implementation is one Python package (chain/) split by concern:
GitHub push
→ webhook.py / github.py signature + diff retrieval
→ analyzer.py incremental repo scan
→ classifier.py / llm.py structured breaking-change judgment
→ graph_store.py / impact.py arbitrary-depth dependent walk
→ notifier.py targeted Slack alert
The FastAPI service includes a visual, single-page demo at /. A judge enters
the access code supplied with the submission, optionally pastes their own Slack
Incoming Webhook URL, and runs one of two fixed, safe scenarios:
- Breaking auth change: GPT-5.6 classifies the diff, the graph highlights one-hop and two-hop impact, and two targeted Slack alerts are delivered.
- Harmless comment: the graph remains safe and zero alerts are generated.
The access code is configured only through CHAIN_DEMO_ACCESS_CODE; it is not
hardcoded in this repository. User-supplied Slack webhook URLs are accepted only
from https://hooks.slack.com/services/..., used for that request, and never
stored or returned. If the field is blank, the server uses its configured demo
Slack channel. Delivery is rate-limited while result previews remain available.
The hosted judge experience is available at chain-api-watch.vercel.app. The submission form provides the access code; leaving the Slack field blank sends alerts to the preconfigured demo channel.
Run the site locally:
export CHAIN_DEMO_ACCESS_CODE="choose-a-demo-code"
uvicorn chain.webhook:app --host 127.0.0.1 --port 8000Then open http://127.0.0.1:8000.
Vercel auto-detects the root app.py FastAPI entry point. Render users can use
the included Blueprint instead. On either host, configure OPENAI_API_KEY,
SLACK_WEBHOOK_URL, and CHAIN_DEMO_ACCESS_CODE as encrypted environment
variables. Do not commit their values. For serverless hosts, also set
CHAIN_GRAPH_PATH=/tmp/chain-graph.json.
Python 3.11+ is required. The demo does not need OpenAI, GitHub, or Slack credentials; missing Slack configuration becomes a clearly labeled dry run.
python3 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
./demo/run_demo.shThe command proves all four acceptance paths:
- Initial analysis creates exactly two edges in the expected three-repo chain.
- The auth diff is classified as
breaking: true. - Impact analysis finds
employee-app-serverat one hop andemployee-appat two hops, including@mina-appand "My HR Info" in the alert. - The next push scans only
hrm-server; a comment-only diff sends no alert.
Useful individual commands:
chain init
chain graph
chain analyze hrm-server --sha example-push-sha
chain classify hrm-server demo/fixtures/breaking_auth.diff
chain simulate
chain demoAll commands can also run as python3 -m chain.cli <command>.
The starting (non-breaking) application is fully runnable. Node.js 18+ is
required because the BFF uses the built-in fetch implementation.
npm --prefix sample-repos/hrm-server install
npm --prefix sample-repos/employee-app-server install
# Run these in three terminals:
npm --prefix sample-repos/hrm-server start
npm --prefix sample-repos/employee-app-server start
npm --prefix sample-repos/employee-app startOpen http://localhost:3000 and click Load profile, or run the automated service smoke test:
./demo/smoke_services.shThe services use ports 3000 (app), 3001 (BFF), and 3002 (HR backend).
The deterministic fallback makes recorded demos reliable. With
OPENAI_API_KEY present, CHAIN_USE_LLM=auto uses the OpenAI Responses API and
Pydantic structured output. The default model is gpt-5.6-sol with high
reasoning effort; both are configurable.
For a lower-cost smoke test, the included .env.example uses
gpt-5.6-luna with low reasoning effort. This keeps the runtime on GPT-5.6
while fitting CHAIN's narrow structured-classification task. Copy and load the
file before running the demo; CHAIN deliberately does not load secret files
automatically.
cp .env.example .env
# Fill OPENAI_API_KEY and, for real delivery, SLACK_WEBHOOK_URL in .env.
set -a
source .env
set +a
CHAIN_USE_LLM=always chain classify hrm-server demo/fixtures/breaking_auth.diff
CHAIN_USE_LLM=always ./demo/run_demo.shWhy the offline fallback exists: a stage demo should still be deterministic if Wi-Fi, model access, or a credential fails. Runtime logs say whether OpenAI or the heuristic produced the classification; Slack dry runs are never reported as delivered messages.
The OpenAI integration follows the current GPT-5.6 model guidance: Responses API, an explicit reasoning setting, and a strict structured result consumed by the graph pipeline.
export GITHUB_WEBHOOK_SECRET="choose-a-long-random-secret"
export GITHUB_TOKEN="github-personal-access-token" # needed for private repos
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/..."
python main.pyConfigure the GitHub webhook URL as:
POST https://<public-host>/webhooks/github
Content type: application/json
Secret: the exact GITHUB_WEBHOOK_SECRET value
Event: push
For a push, CHAIN uses repository.full_name, before, and after to retrieve
the GitHub Compare API patches. It then re-analyzes only repository.name and
persists that analysis record in data/graph.json.
Unsigned webhooks are rejected. CHAIN_ALLOW_UNSIGNED_WEBHOOKS=1 exists only for
local testing and should never be enabled on a public endpoint.
Edit config/repos.json:
{
"name": "orders-web",
"path": "/absolute/path/to/orders-web",
"base_urls": ["https://orders.internal.example"],
"slack_user": "<@U01234567>",
"features": {
"GET /api/orders": "Order history"
}
}base_urls resolve host-to-repository ownership. features maps a caller's
method/path to human-readable product context. Use Slack member IDs such as
<@U01234567> for real mentions; plain handles are still included as readable
text but Incoming Webhooks may not turn them into notifications.
After editing the registry, run chain init once. Later pushes are incremental.
Endpoint handlers are nodes. A standalone frontend call becomes a client_call
node. A call inside an Express handler originates directly from that endpoint:
employee-app:CALL:GET:/api/hr-info
→ employee-app-server:ENDPOINT:GET:/api/hr-info
→ hrm-server:ENDPOINT:GET:/api/employee/profile
When an upstream endpoint breaks, impact analysis follows incoming edges. This
naturally finds callers of callers at any depth. Each edge records the repo whose
analysis produced it. Re-analyzing hrm-server replaces only nodes and edges
owned by hrm-server, preserving all incoming dependency evidence from the BFF
and frontend.
The store is deliberately JSON for hackathon legibility. data/graph.json is
written atomically and keeps the latest 100 scan records so incremental behavior
is visible in the demo.
pytest
python3 -m compileall -q chain tests main.py
./demo/smoke_services.shThe suite covers static extraction, the exact two-edge fixture, BFF dual roles, incremental replacement, auth/removal/safe diff classification, depth-limited and two-hop traversal, targeted Slack content, GitHub HMAC validation, webhook routing, and the complete core flow.
This submission intentionally supports REST/HTTP dependencies, one registry, one JSON store, and Slack only. It does not include a dashboard, graph database, multi-tenant auth, CODEOWNERS/org-chart resolution, email, queues, gRPC, or production job orchestration. See PRD.md for the original scope and acceptance criteria.
