Format 1.0
The record as data
The builder saves every record as a small JSON file. The format is open (MIT), versioned, and described by a JSON Schema, so any tool can read and write it.
JSON Schema draft 2020-12. Schema id: https://openrepairrecord.com/schema/orr-1.0.schema.json
Build a record, step by step
One fictional repair, written as a file one part at a time. Scroll, and the part being explained lights up. The same nine parts are the sections of the builder and of the printed report.
-
1Fundamentals
Every record starts with the format version and your own job number, so any tool knows how to read it and anyone can match it to the original job card.
-
2What was reported
Where, when, who reported it, and the symptom in the reporter's own words. The diagnosis stays out of here: it is the contractor's view, and goes in their statement.
-
3What the contractor says
One entry per visit, each with a name and a time. The outcome is what the contractor reports, not a verdict: resolved, temporary fix, partly done, not done, or no access.
-
4Checks
Who checked, how, what they found, and what they did not cover. Here the technician ran a 15-minute test, and the coordinator reviewed the photo but did not inspect the unit.
-
5Evidence
What backs a statement or a check, with what it shows and who made it. Files stay where they are; the record only names them. Evidence is never required.
-
6The resident
The answer to one question: is the problem solved? This resident was asked on 11 Oct and never answered, so the record says no_reply, with the date. Silence is never a yes.
-
7Still open
Anything left to do, with an owner and a date. Empty here, because the contractor reports a full fix. A temporary fix would need an entry.
-
8Closure
Closing is a decision, so it has an author and a reason. This job was closed as "work reported done, no reply from the resident": honest, and good enough.
-
9Later additions
Whatever comes later is added, never rewritten: a late reply, a revisit, a correction. If the record is reopened, the old closure is kept here exactly as it was.
{
"orr_version": "1.0",
"id": "Q-1204",
"title": "AC dripping water",
"context": {
"location": "Tower 2, Apartment 1204",
"area": "unit",
"asset": "Split AC, living room",
"reported_at": "2026-10-10T16:05",
"reported_by_role": "resident",
"symptom": "Water is dripping from the AC in the living room."
},
"work": [
{
"by": {
"name": "Ravi Kumar",
"company": "Bluepoint Cooling",
"role": "AC technician"
},
"at": "2026-10-11T10:30",
"done": "Cleared the blocked condensate drain, then ran the unit for 15 minutes and watched it: no leak during that time.",
"diagnosis": "Blocked condensate drain.",
"outcome": "resolved"
}
],
"checks": [
{
"by_role": "technician",
"by_name": "Ravi Kumar",
"at": "2026-10-11T10:50",
"method": "test_run",
"result": "Ran the unit for 15 minutes: no water leaked while watching.",
"limits": "15 minutes only."
},
{
"by_role": "coordinator",
"by_name": "Lina Haddad",
"at": "2026-10-11T14:00",
"method": "photo_review",
"result": "The technician's photo and test note are on file.",
"limits": "Did not inspect the unit."
}
],
"evidence": [
{
"type": "photo",
"description": "The drain line after cleaning.",
"taken_by": "Ravi Kumar",
"taken_at": "2026-10-11T10:48",
"reference": "Q-1204-drain.jpg"
},
{
"type": "test_log",
"description": "Technician's note: 15-minute test run, no leak seen.",
"taken_by": "Ravi Kumar",
"taken_at": "2026-10-11T10:50"
}
],
"resident": {
"status": "no_reply",
"asked_at": "2026-10-11T14:05",
"channel": "WhatsApp"
},
"open_items": [],
"status": "closed",
"closure": {
"closed_by": {
"name": "Lina Haddad",
"role": "Maintenance coordinator"
},
"closed_at": "2026-10-15T09:00",
"reason_code": "work_reported_done_no_reply",
"reason": "Work reported as done. Asked the resident on 11 Oct; no reply after four days."
},
"history": [
{
"at": "2026-10-16T08:40",
"by": "Lina Haddad",
"kind": "note",
"text": "Sent this report to the owner as a PDF."
}
]
} Field reference
Every field, with what it means. Generated from the JSON Schema, so this table and the schema always say the same thing. Only the fields marked required must be present; everything else is written when you know it.
Fundamentals
| Field | Type | What it means |
|---|---|---|
orr_versionrequired | always "1.0" | The version of this format. Always "1.0" for files written against this schema, so a reader knows which rules apply. |
id | text | Your own reference for the job: the ticket, work order or job card number in your system. Lets anyone match the record to the original job. e.g. Q-1204 |
title | text | A short, human title for the record. Optional: the report falls back to the symptom. e.g. AC dripping water |
timezone | text | IANA time zone of the property, when the dates need it to be unambiguous. Dates without an offset are read in this zone. e.g. Asia/Qatar |
related_ids[] | list | Other records about the same problem, such as an earlier job that was closed and came back. |
What was reported
| Field | Type | What it means |
|---|---|---|
contextrequired | group | What was reported: where, when, by whom, and the symptom in the reporter's own words. The diagnosis does not go here; it belongs to the contractor's statement. |
context.location | text | Where the problem is: the building and unit, or the common area. e.g. Tower 2, Apartment 1204 |
context.area | one ofunitcommon_area | unit: inside one home, where a resident can be asked. common_area: lobby, plant room, car park, lifts; nobody to ask, so the resident's answer is not_applicable. |
context.asset | text | The equipment, if known: an asset tag from your register or a plain label. Lets repeat faults on the same equipment be found later. e.g. Split AC, living room |
context.reported_at | date | When the problem was reported. e.g. 2026-10-11T10:30 |
context.reported_by_role | one ofresidentownerstaffinspectionother | Who reported it: the resident, the owner, your own staff, a planned inspection, or someone else. |
context.symptom | text | What was reported, in the reporter's terms. Keep it as reported: if the fault comes back, this is what you compare against. e.g. Water is dripping from the AC in the living room. |
What the contractor says
| Field | Type | What it means |
|---|---|---|
work[]required | list | What the contractor says, one entry per visit or report of work, oldest first. Each entry is a statement with a name and a time, not a verdict. |
work[].by | group | Who made the statement: the technician, and their company. |
work[].by.name | text | The person's name. |
work[].by.company | text | Their company. |
work[].by.role | text | Their role, e.g. AC technician or maintenance coordinator. |
work[].at | date | When the work was done, or when the statement was made. e.g. 2026-10-11T10:30 |
work[].done | text | What the contractor says was done, in their words. e.g. Cleared the blocked condensate drain, then ran the unit for 15 minutes. |
work[].diagnosis | text | The contractor's view of the cause, if known. e.g. Blocked condensate drain. |
work[].outcome | one ofresolvedtemporary_fixpartialnot_doneno_access | The outcome the contractor reports. resolved: they believe the fault is fixed. temporary_fix: the symptom is stopped, the real repair is still to come. partial: some of the work is done. not_done: they came but could not do it. no_access: nobody let them in. |
work[].follow_up_needed | yes / no | True when the contractor says another visit or more work is needed. |
work[].follow_up | text | What that follow-up is. e.g. Fit the new drain pan when it arrives. |
Checks
| Field | Type | What it means |
|---|---|---|
checks[]required | list | Anything someone did to confirm the work, oldest first. Each check says who, how, what they found, and what they did not cover. Empty when nobody checked: that is allowed, and the report says so. |
checks[].by_role | one oftechniciancoordinatorinspectorresidentother | Who checked: the technician themselves, your coordinator, an inspector, the resident, or someone else. |
checks[].by_name | text | The name of the person who checked. |
checks[].at | date | When the check was done. e.g. 2026-10-11T10:30 |
checks[].method | one oftest_runmeasurementvisualphoto_reviewother | How it was checked: running the equipment, measuring something, looking at it, reviewing a photo, or another way. |
checks[].result | text | What the check found. e.g. Ran the unit for 15 minutes: no water leaked while watching. |
checks[].limits | text | What the check did not cover. As useful as the result: it tells the reader where the knowledge stops. e.g. Did not inspect the unit. |
Evidence
| Field | Type | What it means |
|---|---|---|
evidence[]required | list | What backs a statement or a check: photos, measurements, test logs, certificates. Never required. The record lists them; it does not store or upload them. |
evidence[].type | one ofphotomeasurementtest_logcertificatedocumentother | What kind of evidence it is. |
evidence[].description | text | What it shows. A photo shows what it shows; say what that is. e.g. The drain line after cleaning. |
evidence[].taken_by | text | Who made it. |
evidence[].taken_at | date | When it was made. e.g. 2026-10-11T10:30 |
evidence[].reference | text | A file name or a link to where it is kept. Nothing is uploaded. e.g. Q-1204-drain.jpg |
The resident
| Field | Type | What it means |
|---|---|---|
residentrequired | group | The resident's answer to one question: is the problem they reported solved, in their view? |
resident.statusrequired | one ofresolvednot_resolvednot_askedpendingno_replynot_applicable | resolved: they say it is solved. not_resolved: they say it is not. not_asked: nobody asked yet. pending: asked, waiting for an answer. no_reply: asked and nothing came back; stays no_reply, silence is never a confirmation. not_applicable: there is no resident to ask (common areas). |
resident.asked_at | date | When the resident was asked. This is what makes no_reply meaningful. e.g. 2026-10-11T10:30 |
resident.answered_at | date | When the resident answered. e.g. 2026-10-11T10:30 |
resident.words | text | The resident's own words, quoted as written. e.g. It's dripping again, same place. |
resident.channel | text | How they were asked or answered. e.g. WhatsApp |
Still open
| Field | Type | What it means |
|---|---|---|
open_items[]required | list | Anything still left to do. A temporary fix or partial work needs at least one entry, with an owner and a date. |
open_items[].what | text | What is still open. e.g. Fit the new drain pan. |
open_items[].owner | text | Who owns it. e.g. Ravi Kumar, Bluepoint Cooling |
open_items[].next_step | text | The next concrete step. |
open_items[].due | date | By when. e.g. 2026-10-11T10:30 |
Closure
| Field | Type | What it means |
|---|---|---|
statusrequired | one ofopenclosed | Whether the record is open or closed. Closing is a decision someone takes; the closure says who and why. |
closure | group | Present only while the record is closed: who closed it, when, and why. |
closure.closed_by | group | Who closed it. |
closure.closed_by.name | text | The person's name. |
closure.closed_by.company | text | Their company. |
closure.closed_by.role | text | Their role, e.g. AC technician or maintenance coordinator. |
closure.closed_at | date | When it was closed. e.g. 2026-10-11T10:30 |
closure.reason_code | one ofconfirmed_by_residentwork_reported_done_no_replyadministrativeduplicatecancelledother | Why. confirmed_by_resident: the resident said it is solved (needs resident.status resolved). work_reported_done_no_reply: the contractor reported it done and the resident did not answer. administrative: closed for an organisational reason, explained in reason. duplicate: the same problem is tracked in another record. cancelled: the job was cancelled. other: explained in reason. |
closure.reason | text | The reason in your own words. e.g. Work reported as done. Asked the resident on 11 Oct; no reply after four days. |
Later additions
| Field | Type | What it means |
|---|---|---|
history[]required | list | Later additions, oldest first: a late reply, a revisit, a correction, a reopening. Earlier entries are never rewritten; changes are added here. |
history[].at | date | When this was added. e.g. 2026-10-11T10:30 |
history[].by | text | Who added it. |
history[].kind | one ofresident_replyrevisitcorrectionreopenednote | resident_reply: an answer that came in later. revisit: another visit. correction: a fix to something written earlier, without rewriting it. reopened: a closed record was opened again. note: anything else. |
history[].text | text | What the addition says. |
history[].previous_closure | group | For reopened: the closure that was in force before, kept exactly as it was. |
history[].previous_closure.closed_by | group | Who closed it. |
history[].previous_closure.closed_by.name | text | The person's name. |
history[].previous_closure.closed_by.company | text | Their company. |
history[].previous_closure.closed_by.role | text | Their role, e.g. AC technician or maintenance coordinator. |
history[].previous_closure.closed_at | date | When it was closed. e.g. 2026-10-11T10:30 |
history[].previous_closure.reason_code | one ofconfirmed_by_residentwork_reported_done_no_replyadministrativeduplicatecancelledother | Why. confirmed_by_resident: the resident said it is solved (needs resident.status resolved). work_reported_done_no_reply: the contractor reported it done and the resident did not answer. administrative: closed for an organisational reason, explained in reason. duplicate: the same problem is tracked in another record. cancelled: the job was cancelled. other: explained in reason. |
history[].previous_closure.reason | text | The reason in your own words. e.g. Work reported as done. Asked the resident on 11 Oct; no reply after four days. |
Dates are ISO 8601 as written: 2026-10-12 or 2026-10-12T14:20, in the property's local
time unless an offset is given. Text is free text: the format does not impose code lists beyond the few
choices above, which every report needs so that it is read the same way.
Rules
The schema checks the shape. A few rules are about meaning, and the builder's check applies them:
resident.statusno_replystaysno_reply. No tool should turn silence intoresolved.- An open record has no
closure. Reopening moves the old closure intohistory[].previous_closure, unchanged. closure.reason_codeconfirmed_by_residentneedsresident.statusresolved.- A latest
workoutcome oftemporary_fixorpartialneeds at least oneopen_itemsentry. not_applicableis for common areas. Evidence is never required.- Entries are added, not rewritten. Corrections go in
history.
Example files
- kitchen-tap.json · A normal repair, confirmed
- ceiling-leak.json · A temporary fix
- ac-no-reply.json · No reply from the resident
- ac-reopened.json · Dripping again: reopened
- no-access.json · No access
How it relates to existing models
Open Repair Record is a practical guide and a small format for one report. It is not a new data standard for housing, and it does not replace the models that already exist:
- HACT UK Housing Data Standards cover reactive repairs among much else. We have not mapped ORR to them; if you use them, keep using them.
- MIMOSA CCOM, COBie and OSCRE model assets, completed work and property data in far more depth.
The closest public schema we have read is the
damp-and-mould data standards proof of concept
(data-futurists, MIT, 2025). Its own README says it is a proof of concept, not finalised, and not for live
services. The table below is our informal reading of its work_order definitions, not an official
mapping:
| Open Repair Record | Damp-and-mould proof of concept | Note |
|---|---|---|
id | work_order_id | |
context.reported_at | date_reported | |
context.location | address_id, location_of_repair | theirs is an address identifier plus where in the home |
context.symptom | description_of_work | theirs describes the problem from a schedule of rates or a local code |
work[].at | actual_start_date_time, actual_completion_date_time | ORR keeps one time per statement |
work[].by | contractor_organisation, work_order_complete.operatives_used | |
work[].done | work_order_complete.completed_work_elements | |
work[].follow_up, open_items[] | work_order_complete.follow_on_work | theirs is a single text field |
status, closure, history[] | work_order_status_history (status_code, reason, reason_code, created_date_time), job_status_update | codes are free text in both |
checks[], evidence[], resident | no equivalent in the work_order definitions | |
not in ORR | work_priority, planned dates, estimated_cost, repair_sla_breach_flag, access information, alerts, trade and schedule-of-rates codes | left to the operator's own system |
The gap is the point: work-order models describe the job; ORR adds who checked what, what the resident answered, and why the record was closed. If an existing model covers what you need, use it, and treat ORR as a guide for filling it in well.
Versions
The promise: every 1.x version only adds. A file written for 1.0 stays valid in 1.1, 1.2 and later, and its fields keep their meaning. Anything that would break a file waits for 2.0, and is announced here first.
| Version | Status | What it brings |
|---|---|---|
| 1.0 | Current 18 Oct 2026 | The nine parts of a record, the JSON Schema, the builder with its check, print and PDF, five examples. |
| 1.1 | Planned | A bilingual English and Arabic report, reviewed by a native speaker who knows local maintenance terms. Optional language field. |
| 1.2 | Planned | A draft from a technician's note: each statement keeps the words it came from, and a person confirms it. Optional source on each entry. |
| 1.3 | Planned | Links to an asset register: equipment identifiers and a repeat-fault history for the same asset. |
Planned versions are intentions, not dates. Tell us what you need first: support@pmfriend.com.