The portable, verified safety record for industrial workers. Built once. Trusted everywhere.
Cairn is an AI-powered worker safety credential platform, anchored on NEAR Protocol.
Workers build a verified safety identity — training certificates, incident-free history, site clearances, verified wage records — that follows them across every employer. Site managers get an AI compliance co-pilot: real-time hazard detection from daily photo check-ins, AI-classified incident reports, and one-click credential and wage issuance that settles on-chain. Every record is owned by the worker and independently verifiable by anyone, forever.
No paperwork. No employer lock-in. No re-proving your safety record from zero at every new site.
| Worker Dashboard | Manager Compliance Overview |
|---|---|
![]() |
![]() |
| Sign-In Page | Safe Workers |
![]() |
![]() |
All product screenshots are live captures from the Cairn platform.
| Resource | Link |
|---|---|
| Live App | cairn-theta-seven.vercel.app |
| GitHub | github.com/0xkinno/cairn |
| Demo Video | Youtube |
| NEAR Testnet Explorer | testnet.nearblocks.io/address/cairn-deployer.testnet |
| Hackathon | ChainHack 2026 / NeuralLedger 5.0 — Real-World Applications (primary), AI × Web3 (secondary) |
Industrial safety records are stuck with the employer, not the worker.
An electrician who spends three years building an incident-free record, earning site clearances, and completing safety certifications at one construction firm walks away with nothing when they change employers. The new site has no way to verify any of it. So the worker starts from zero: retraining, re-certifying, re-proving competence the site manager has no reason to trust yet, because the paper trail — if it exists at all — lives in a filing cabinet at the old company.
This isn't a hypothetical. Fewer than 8% of safety records in Southeast Asian industrial sites are digitized in any verifiable form. Site managers run compliance largely on manual inspection — walking the floor with a clipboard — while OSHA-equivalent bodies report 2.3 million workplace deaths annually worldwide, a huge share preventable with earlier hazard detection. Meanwhile the ASEAN infrastructure buildout alone represents a $2 trillion pipeline of sites that all face the same problem: no portable trust layer for the people doing the work.
Two failures compound here. First, workers have no ownership of their own safety history — it's fragmented across employers who have no incentive to make it portable. Second, site managers have no real-time signal — by the time a hazard becomes an incident, it's already too late to have caught it with a photo and a model that costs cents to run.
Cairn gives the worker a portable, cryptographically-verifiable identity, and gives the site manager an AI safety engine that runs on every single check-in.
A worker signs up, completes onboarding, and joins a site with an invite code. Every day, they check in with a photo and an optional voice or text note. Google Gemini analyzes the photo in real time — missing PPE, trip hazards, electrical exposure, housekeeping issues — and returns a structured hazard report in seconds, not a form that sits in a drawer. That check-in, its AI analysis, and the resulting safety-score update are all hashed and attested on a NEAR smart contract. When a site manager issues a credential or approves a wage record, that too is signed and recorded on-chain.
The result: a single QR code on the worker's phone opens a public verification page — no login required — that proves safety history, credentials, and verified pay to any future employer, instantly, without asking the worker's old company for anything.
Worker checks in: photo + note, submitted from job site
Gemini analysis: hazard detection, ISO 45001 categorization, < 15s
Safety score: recomputed from streak, incidents, hazard rate
On-chain attestation: ledger.cairn-deployer.testnet.attest_checkin()
Verification: /verify/[workerId] — public, no auth, always live
flowchart TD
A["Worker signs up & completes onboarding"] --> B["Worker joins a site\nvia manager's invite code"]
B --> C["Daily check-in:\nphoto + optional voice/text note"]
C --> D["Gemini Vision API\nanalyze-hazard"]
D --> E["Structured hazard report:\nseverity, ISO 45001 clause, recommended action"]
E --> F["Supabase: checkins + hazard_flags rows"]
F --> G["Safety score recomputed\n(streak, incidents, hazard rate)"]
G --> H["NEAR: safety-ledger.attest_checkin()\n+ checkpoint_score()"]
E --> I{"Manager reviews hazard feed\nin real time"}
I -->|"Files incident"| J["Gemini: classify-incident\nseverity, root cause, corrective actions"]
J --> K["NEAR: safety-ledger.record_incident_hash()"]
I -->|"Issues credential"| L["NEAR: credential-vault.issue_credential()"]
I -->|"Approves wage"| M["NEAR: safety-ledger.record_wage_hash()"]
H --> N["Public verification page\n/verify/[workerId]"]
L --> N
M --> N
N --> O["Any employer scans QR,\nverifies instantly, no login"]
+----------------------------------------------------------------------+
| Next.js 16 App Router (Turbopack) |
| |
| PAGES API ROUTES |
| / Landing (10 sections) /api/ai/* Gemini calls|
| /register /login Auth /api/checkins Check-in |
| /onboarding Role + profile setup /api/incidents Incidents |
| /worker/* Dashboard, check-in, /api/workers Roster |
| credentials, wages /api/wages Payroll |
| /manager/* Overview, roster, /api/credentials Issuance |
| incidents, wages, /api/organizations Org mgmt |
| analytics, reports /api/near/* Chain calls|
| /verify/[id] Public verification /api/reports/* Compliance |
| (no auth) |
+---------------------------+-------------------+----------------------+
| |
+-------------+ +---------+------------------+
v v v
+----------------------------+ +--------------------+ +---------------------------+
| Google Gemini | | Supabase Postgres | | NEAR Protocol (testnet) |
| (gemini-flash-latest) | | | | |
| | | 10 tables, RLS on | | 4 near-sdk-js contracts: |
| analyze-hazard (vision) | | every table: | | cairn-registry |
| classify-incident (text) | | workers | | credential-vault |
| safety-tips (text) | | organizations | | safety-ledger |
| intelligence (predictive) | | org_members | | org-registry |
| | | worker_assignments | | |
| Structured JSON out, | | credentials | | Deployed & verified live: |
| ISO 45001-aligned | | checkins | | reg.cairn-deployer.testnet|
| categorization | | incidents | | vault.cairn-deployer.tn |
| | | hazard_flags | | ledger.cairn-deployer.tn |
| | | score_history | | org.cairn-deployer.tn |
| | | wage_records | | |
| | | + Storage (photos) | | Every check-in, credential|
| | | + Realtime (hazards) | | wage, and incident writes |
+----------------------------+ +--------------------+ | a real signed transaction |
+---------------------------+
sequenceDiagram
participant W as Worker (mobile)
participant App as Cairn (Next.js server)
participant AI as Gemini Vision
participant DB as Supabase
participant Chain as NEAR safety-ledger
W->>App: POST /api/ai/analyze-hazard (photo, note)
App->>AI: generateContent([prompt, image])
AI-->>App: hazards_detected[], overall_risk_level, ISO clause
App-->>W: render AIAnalysisResult
W->>App: POST /api/checkins (photo, analysis)
App->>DB: upload photo to Storage
App->>DB: insert checkins row
App->>DB: insert hazard_flags rows (one per hazard)
App->>DB: recompute safety_score, insert score_history
App->>Chain: attest_checkin(checkin_id, worker_id, sha256(data))
Chain-->>App: tx hash (SuccessValue)
App->>DB: update checkins.near_attestation_hash
App->>Chain: checkpoint_score(worker_id, score, sha256(breakdown))
Chain-->>App: tx hash
App->>DB: update score_history.near_checkpoint_hash
App-->>W: redirect to /worker/checkin/[id]
Every check-in photo goes through Gemini's multimodal vision API and comes back with a structured report: hazard type (missing PPE, trip hazard, electrical exposure, housekeeping, machine guarding, and 9 more categories), severity, confidence score, exact location in the image, recommended corrective action, and the relevant ISO 45001 clause. Positive observations are called out too — the model isn't just hunting for violations. Confirmed live: a real welding photo correctly flagged bare-handed arc welding as a high-severity missing-PPE hazard at 95%+ confidence.
Managers file incidents in plain language. Gemini classifies severity (near-miss through fatality), root cause categories, contributing factors, affected body parts, equipment involved, the relevant ISO 45001 clause, a prioritized list of corrective actions with responsible party, and investigation questions — the same structure a real safety officer would produce, generated in seconds.
- cairn-registry — worker identity registration
- credential-vault — credential issuance, verification, revocation
- safety-ledger — check-in attestation, score checkpoints, incident hashes, wage hashes
- org-registry — organization registration and issuer management
Every check-in, credential, incident, and wage approval writes a real signed transaction to testnet. Nothing is simulated — every hash in the app is independently verifiable by calling the contract's own view methods.
A single QR code opens /verify/[workerId] — no login, no account needed by the person checking it. Three tabs: Safety Record (score, streak, total check-ins), Credentials (with NEAR proof links), Wage History (verified earnings with NEAR proof links). This is the entire pitch made physical: one link proves what used to require a phone call to a previous employer.
Score is a weighted composite: consistency (streak + check-in rate, 25%), incident severity (30%), credential coverage (25%), 30-day hazard rate (20%). Recomputed after every check-in, checkpointed on-chain, with full history in score_history. Verified live moving 50 → 73 after a single real check-in with one detected hazard.
Real-time hazard feed via Supabase postgres_changes subscriptions (no polling), worker roster scoped correctly to the manager's own organization, incident board (open / investigating / resolved), credential issuance with NEAR signing, wage management with CSV export and on-chain approval, a D3-scaled hazard-density-by-zone visualization, and Gemini-generated predictive risk intelligence (trend, top risks, positive trends) computed from the org's actual 30-day data.
Wage periods are entered by the manager (shifts, hours, overtime, rates), gross/net computed automatically, hashed with SHA-256, and — on approval — written to the safety-ledger contract's record_wage_hash(). The worker sees a running yearly-earnings total with every period's NEAR proof link, visible on both their private dashboard and the public verification page.
Every number in this app — safety scores, hazard counts, wage totals, credential lists — is queried live from Postgres or computed from a real Gemini/NEAR call. There is no seed script generating fake workers or fake incidents. What you see when you run this locally is what actually happened when you clicked the buttons.
Editorial, monochrome-with-warm-undertone visual language — deliberately not the default AI-generated cream/terracotta palette, not Inter, no component library, no SVG illustrations.
| Element | Specification |
|---|---|
| Display/headline type | Instrument Serif, 400 weight, fluid clamp() sizing |
| Body/UI type | Plus Jakarta Sans, 300–700 weight |
| Data/mono labels | IBM Plex Mono, uppercase, letterspaced |
| Background | Warm off-white #FAFAF7, never pure white |
| Accent | Safety amber #D4940A (#E8A317 in dark mode) |
| Status colors | Desaturated safe/warning/critical/info, not neon |
| Card radius | 0px cards (borderless, spacing-separated), 8px buttons, 100px pills |
| Loading state | Skeleton screens only — no spinners, anywhere |
| Motion | Framer Motion, cubic-bezier(0.22, 1, 0.36, 1), scroll-triggered reveals |
| Photography | Real, content-verified Unsplash photography, warm color grade (saturate(0.9) brightness(1.02)) |
| Theming | Full light/dark token support via [data-theme] |
IDENTITY
workers id, user_id, near_account, safety_score, score_breakdown,
streak/checkin counters, preferred_language
organizations id, owner_id, near_account, site_safety_score, invite_code
org_members org_id, user_id, role, can_issue_credentials
worker_assignments worker_id, org_id, status (join-by-invite-code)
SAFETY
checkins worker_id, org_id, photo_url, ai_analysis (jsonb),
overall_risk, hazards_count, near_attestation_hash
hazard_flags checkin_id, hazard_type, severity, confidence, iso_category
incidents org_id, severity, ai_classification (jsonb),
corrective_actions, status, near_tx_hash
score_history worker_id, score, breakdown (jsonb), near_checkpoint_hash
CREDENTIALS & PAY
credentials worker_id, issuer_org_id, credential_type, status, near_tx_hash
wage_records worker_id, org_id, pay_period, gross/net_pay, pay_hash, near_tx_hash
All 10 tables have row-level security enabled. Public-read policies exist specifically on workers (active only), credentials, and wage_records — the exact three tables the verification portal needs, and nothing else.
| Contract | Testnet account | Key methods |
|---|---|---|
| CairnRegistry | reg.cairn-deployer.testnet |
register_worker, get_worker, deactivate_worker |
| CredentialVault | vault.cairn-deployer.testnet |
issue_credential, verify_credential, revoke_credential |
| SafetyLedger | ledger.cairn-deployer.testnet |
attest_checkin, checkpoint_score, record_incident_hash, record_wage_hash, verify_record |
| OrgRegistry | org.cairn-deployer.testnet |
register_org, add_issuer, get_org |
Written in TypeScript with near-sdk-js, compiled to WASM (QuickJS runtime embedded, ~530KB per contract — the tradeoff for writing contracts in TS instead of Rust), deployed as sub-accounts of a funded deployer account, each staked with its own storage deposit per NEAR's ~1 NEAR/100KB protocol rule.
Every write path in the app (lib/near/contracts.ts) calls the real contract and stores the resulting transaction hash next to the Postgres row it corresponds to — visible directly in the UI and independently checkable via verify_record / verify_credential / get_worker view calls.
| Method | Path | Description |
|---|---|---|
| POST | /api/ai/analyze-hazard |
Gemini vision hazard analysis from a photo |
| POST | /api/ai/classify-incident |
Gemini text classification of an incident description |
| POST | /api/ai/safety-tips |
Contextual safety tips for a role/site type |
| POST | /api/ai/intelligence |
Predictive risk brief from an org's rolling 30-day data |
| GET/POST | /api/checkins |
List / create a check-in (uploads photo, runs full attestation chain) |
| GET/POST | /api/incidents |
List / file an incident (AI classify + on-chain hash) |
| PATCH | /api/incidents/[id] |
Resolve an incident |
| GET | /api/workers |
Manager's org roster |
| GET | /api/workers/[id] | /score | /checkins |
Worker detail, score history, check-in history |
| GET/POST | /api/wages |
List / create a wage record |
| POST | /api/wages/[id]/approve |
Approve + record on-chain |
| GET | /api/credentials |
Org's issued credentials |
| POST | /api/near/register |
Register worker or org on-chain |
| POST | /api/near/issue-credential |
Issue credential with real NEAR signing |
| GET | /api/near/verify |
Generic on-chain lookup (worker/org/credential/checkin/incident/wage) |
| GET/POST/PATCH | /api/organizations, /mine, /join |
Org creation, own-org settings, worker join-by-code |
| POST | /api/reports/generate |
Compliance report from live org data |
Requirements: Node.js 20+, npm. WASM contract builds require Docker or a Linux environment (near-sdk-js doesn't build natively on Windows) — not needed unless you're redeploying contracts.
git clone https://github.com/0xkinno/cairn.git
cd cairn
npm install
cp .env.example .env.local # fill in Supabase, Gemini, NEAR credentials
npm run dev # http://localhost:3000Apply the schema once against your Supabase project via the SQL Editor:
# paste the contents of supabase/migrations/001_initial_schema.sql| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Yes | Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Yes | Supabase anon/publishable key |
SUPABASE_SERVICE_ROLE_KEY |
Yes | Service-role key (server-only; several tables have no client-safe RLS policy for cross-role reads) |
GEMINI_API_KEY |
Yes | Google AI Studio key |
NEAR_NETWORK_ID |
Yes | testnet |
NEAR_NODE_URL |
Yes | https://rpc.testnet.near.org |
NEAR_CONTRACT_REGISTRY / _VAULT / _LEDGER / _ORG |
Yes | Deployed contract sub-account IDs |
NEAR_DEPLOYER_ACCOUNT_ID / _PRIVATE_KEY |
Yes | Service account NEAR uses for system-initiated writes |
NEXT_PUBLIC_APP_URL |
Yes | Deployed app URL (used in QR codes, verification links) |
npm run build # production build, zero TypeScript errors across 40 routes- Register + confirm a worker account, complete onboarding, land on
/worker - Register + confirm a manager account, create an organization, get a real invite code
- Worker joins the org via invite code from
/worker/settings - Worker completes a check-in with a real photo — Gemini returns a genuine hazard analysis
- Check-in triggers a real
attest_checkintransaction — confirmed via direct NEAR RPCtxlookup, statusSuccessValue - Manager sees the worker in
/manager/workers, the hazard in the live feed, updated compliance stats - Manager issues a credential — confirmed on-chain via
vault.*.verify_credential - Manager records + approves a wage — confirmed on-chain via
ledger.*.verify_record - Manager files an incident — real Gemini classification + real on-chain hash
/verify/[workerId]shows the same credential and wage NEAR proof hashes, publicly, with zero authentication- Landing page's Live Demo Widget runs a real Gemini analysis with no sign-up
- Zero horizontal overflow confirmed at 375px, 768px, and 1440px viewports
Cairn targets Real-World Applications (primary) and AI × Web3 (secondary) for ChainHack 2026 / NeuralLedger 5.0, with triple sponsor alignment:
- NEAR Protocol (Gold) — the entire trust layer. Four deployed contracts, not a token-gate afterthought: every check-in, credential, incident, and wage writes a real transaction.
- Google Cloud (Platinum) — Gemini powers hazard detection, incident classification, and predictive intelligence — multimodal vision analysis, not a canned response.
- AWS (Platinum) — Supabase's infrastructure runs on AWS underneath.
What differentiates this from a generic safety app: multi-modal AI vision analysis running on every check-in (not a form), portable on-chain credentials the worker owns outright, wage verification alongside safety records (most competitors do one or the other), predictive safety intelligence generated from real org data, and a live public verification page that needs zero backend trust from the viewer — they're reading directly off NEAR.
Stated plainly.
Testnet, not mainnet. All NEAR contracts are deployed to testnet. Moving to mainnet requires re-deployment, real NEAR for storage staking, and a production key-management strategy for the service account (currently a single deployer key signs all system-initiated writes).
org_members and worker_assignments have no client-facing RLS policies. This was a genuine gap discovered during Phase 6 testing — both tables have row-level security enabled but zero policies of their own. Every read of them is routed through the service-role key after verifying the session server-side (lib/supabase/manager-guard.ts), not through direct client queries. This works correctly but means those two tables are effectively server-only.
Contract size is fixed at ~530KB. near-sdk-js bundles a full QuickJS JavaScript engine into every WASM output regardless of contract complexity. This is the reason storage staking costs real NEAR (~5.5 NEAR per contract) — a Rust rewrite would shrink this dramatically but was out of scope given the spec's explicit TypeScript requirement.
No org-level safety score aggregation job. organizations.site_safety_score doesn't currently roll up from individual worker scores automatically — it's set at creation and would need a scheduled job to stay live.
Single deployer key for all on-chain writes. There's no per-manager NEAR wallet signing flow yet (CredentialIssueForm uses the app's own service account, not the manager's personal wallet) — a real production version would move to wallet-selector-based client-side signing for managers.
MIT
Built for ChainHack 2026 / NeuralLedger 5.0. Demo Day: August 8, 2026.




