尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
A small demo of an AI decision layer for truck breakdowns. When a truck throws a fault code, Breakdown Desk:檢視完整 README ↗
A small demo of an AI decision layer for truck breakdowns.
When a truck throws a fault code, Breakdown Desk:
FaultEvent.stop_now / limp_to_shop / schedule_later), decides whether a tow is needed, picks the shops to ask and checks whether the repair is recoverable under warranty.Every step streams live to a dashboard through Supabase Realtime.
Six layers, run in order by lib/pipeline.ts, following Elmeeda's ontology:
Signals → Units → Decisions → Actions → Counterparties → Records
| Layer | Code | What it does |
|---|---|---|
| Signals | app/api/signals/[source], lib/adapters/* | Webhook per source (geotab, samsara, driver) → FaultEvent |
| Units | lib/units.ts | Truck, current load, warranty coverage |
| Decisions | lib/decisions/* | Severity, tow need, shop set, warranty recoverability |
| Actions | lib/pipeline.ts | Call capable shops for quotes |
| Counterparties | lib/counterparties.ts, lib/actions.ts | Shops answer in parallel, quote_accept, then templated booking, driver SMS and warranty claim (pending) |
| Records | lib/records.ts | Repair order and claim line (stand-in for the fleet's maintenance system or TMS) |
The core logic is in lib/decisions/severity.ts:
stop_now. The LLM is not called.stop_now result, or an LLM confidence below 0.7, is marked as needing approval.limp_to_shop, so it is never auto-approved. A driver report with no milepost stops before shop selection and asks dispatch to confirm the location instead of guessing one.rule, llm or human), its reason and its inputs.lib/llm.ts is the only file that calls an AI provider (OpenAI, structured JSON output). Everything else is rules and templates.
| Button | Source | Expected path |
|---|---|---|
| Oil pressure critical | Geotab | Rule → stop_now, tow, needs approval |
| DPF warning | Samsara | LLM → limp_to_shop, under warranty → OEM dealer |
| Slow tire leak | Driver SMS | schedule_later, auto-approved |
Next.js (App Router) + TypeScript + Tailwind, Supabase (Postgres + Realtime), OpenAI SDK, deployed on Vercel. No orchestration framework. No user login (see Security notes).
npm install
In the Supabase dashboard, open SQL Editor and run these two files in order:
supabase/schema.sql creates the tables, the security settings and the Realtime publication for incident_events.supabase/seed.sql adds the trucks, the shops along I-80, the warranty policies and the loads.schema.sql drops and recreates its tables, so you can re-run both files to reset everything.
cp .env.example .env.local
Then fill in .env.local:
| Variable | Where to find it |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Supabase → Project Settings → API |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Same page (anon / public key). The browser uses it to subscribe to the live feed. |
SUPABASE_SERVICE_ROLE_KEY | Same page (service role). Server only. Never expose it. |
OPENAI_API_KEY | platform.openai.com |
OPENAI_MODEL | Optional. Defaults to gpt-4o-mini. |
SIGNALS_WEBHOOK_SECRET | Any long random string, e.g. openssl rand -hex 32. Required to call /api/signals/*; the webhook rejects every call while it is unset. |
npm run dev
Open http://localhost:3000 and click a scenario button. The layer bar and the live feed fill in as the pipeline runs (with about 400 ms between steps so it stays readable). Approve pending actions from the incident panel. Reset clears incidents but keeps the reference data.
npm test
Vitest covers the safety logic with no database or OpenAI calls: driver keyword classification and location parsing, the severity rule floors, the "LLM can escalate but never downgrade" guarantee, the approval thresholds, and which drafted actions auto-approve. The Supabase writes and the live LLM call are exercised by the demo scenarios rather than unit tests.
The scenario buttons replay fixed payloads through /api/scenarios/[id]. To send your own payload, call the webhook with the shared secret:
curl -X POST http://localhost:3000/api/signals/driver -H 'content-type: application/json' -H "x-webhook-secret: $SIGNALS_WEBHOOK_SECRET" -d '{"channel":"sms","receivedAt":"2026-10-02T03:02:16Z","driver":{"name":"Marcus Hale"},"unitNumber":"4590","message":"Left rear drive tire is losing air slowly, about 3 psi an hour. Still rolling fine on I-80 E near MP 284."}'
The call returns 202 { incidentId } right away, and the pipeline keeps running in the background. See lib/mockPayloads.ts for example Geotab and Samsara payloads.
| Method | Route | Purpose |
|---|---|---|
POST | /api/signals/[source] | Ingest a fault (geotab, samsara or driver). Needs the x-webhook-secret header |
POST | /api/scenarios/[id] | Run one of the three demo scenarios (oil, dpf, tire) from the dashboard |
GET | /api/incidents/[id] | Incident with its truck, load, decisions, actions, records and events |
POST | /api/actions/[id]/approve | Human approval of a pending action |
POST | /api/reset | Clear runtime data |
This is a demo, and these are the trade-offs made on purpose:
incident_events (the live feed) and nothing else./api/signals/* accepts arbitrary payloads, so it requires a shared secret (x-webhook-secret) and fails closed when none is configured.The app deploys to Vercel as a standard Next.js app. Set the same environment variables in the Vercel project settings.