Skip to content
Tilfang

Capability Schema

A shared language for what the world can do.

Published concept artefact · describes a design, not a running system

A capability declaration states what a resource can do, where it can do it, how soon, and who must consent — precisely enough to be found, compared and booked. This is v0.1, published 13 August 2026: not a described vocabulary but a schema you can write in — a validatable JSON Schema with this site’s entire 32-resource catalogue embedded as conformant example declarations.

One box of five — on purpose.

Saying what a schema does not define is the honest half of defining it. A declaration describes the resource; everything that happens to one — discovery, booking, planning, evidence — has its own record, and cost lives in the booking, never here.

  1. 01

    Capability declaration

    What a resource can do, where, how soon, who consents

    This schema — the only box it defines

  2. 02

    Discovery & comparison

    Finding candidates and comparing them on the declared attributes

    Consumes declarations

  3. 03

    Booking

    One resource, one mission, one window — where cost lives

    Out of schema, by decision

  4. 04

    Governed mission plan

    The approvals gathered, the constraints checked

    Out of schema

  5. 05

    Evidence record

    What actually happened, with provenance

    Out of schema

Seven classes every mission resolves into.

Missions do not ask for devices — they ask for these. Each class is answered by many resource classes with different trade-offs; the platform page carries 32 worked examples, and every one of them ships in the schema’s example set.

  • Observe

    6 resource classes

    Acquire imagery or signals of a target or area.

  • Measure

    5 resource classes

    Quantify a physical property to a defined quality.

  • Track

    4 resource classes

    Follow an object or signal across time and space.

  • Inspect

    4 resource classes

    Examine an asset for condition, defects, or anomalies.

  • Retrieve

    5 resource classes

    Access existing records, archives, or reference data.

  • Analyse

    4 resource classes

    Turn raw data into validated findings.

  • Report

    4 resource classes

    Produce a verifiable, provenance-rich output.

See the classes with their resource classes and attributes: the capability graph

The declaration, field by field.

Five required fields, four optional ones. The required core is deliberately the set every class — from a satellite payload to a human reviewer — can answer; everything domain-specific lives in extensions.

Capability declaration fields: name, type, what each declares, and an example value
FieldTypeDeclaresExample
capabilityClassrequiredstring (enum of 7)Which of the seven capability classes the resource answers. The class set is closed in v0.1 — the extensibility note carries that argument."inspect"
resourceClassrequiredstringWhat kind of thing provides the capability — a class of resource, never a make, model or company name (write “drone-mounted thermal camera”, not a product name). The specific unit binds at booking, not here."Drone + thermal camera"
reachrequiredstringCoverage geometry: which part of a target it can actually get to. Reach is why two resources answering the same capability are not interchangeable."Roof and façade, close range"
leadTimerequiredstringHow soon it can deliver once booked — from “immediate” (an archive) to “weeks, by availability” (a certified inspector). A mission with a season boundary selects on this before anything else."Hours, weather permitting"
approvalrequiredarray of strings, min 1Consents, clearances and standing authorisations, roughly in the order obtained. An element may name a compound consent granted as one unit; a conditional clearance states its condition. Declaring this up front is what lets a plan carry its permissions instead of discovering them mid-mission.["Aviation authority", "Site owner"]
statusstring (enum of 6)Where the resource stands on the onboarding path. Defaults to “described” — which is also the honest value of every example on this site: nothing is cleared."described"
conditionsarray of stringsOperating constraints the declaration owns up to — weather windows, daylight, co-registration, staffing. A constraint declared here is one a mission plan can check instead of trip over.["Daylight or a stated thermal window"]
extensionsobject (namespaced)Per-domain attributes under a lowercase namespace key, carrying your real measured values, with units. Domain measures never enter the required core.{ "sensing": { "resolution": "…" } }
declaredByobjectWho is declaring — operator name, contact, date. Optional because the comparison works anonymously; named, the declaration becomes yours to send, and to be credited for.{ "operator": "…", "date": "…" }

A declaration may also carry "$schema" pointing at this schema, for editor tooling — meta, not vocabulary.

Three declarations, written out.

Copy one, replace the values with an asset you actually operate, and validate it — that is the whole experiment. Every example declares "status": "described", because that is the truth: nothing on this site has passed a single onboarding gate. Add the optional declaredBy block and send it — real declarations enter the v0.2 changelog, with credit.

Drone + thermal camera · inspect
{
  "capabilityClass": "inspect",
  "resourceClass": "Drone + thermal camera",
  "reach": "Roof and façade, close range",
  "leadTime": "Hours, weather permitting",
  "approval": [
    "Aviation authority",
    "Site owner"
  ],
  "status": "described",
  "conditions": [
    "Daylight or a stated thermal window",
    "Wind below the platform’s operating limit"
  ],
  "extensions": {
    "sensing": {
      "resolution": "Thermal ground resolution at survey distance",
      "threshold": "Declared against the mission’s stated defect size"
    }
  }
}
Satellite imagery archive · retrieve
{
  "capabilityClass": "retrieve",
  "resourceClass": "Satellite imagery archive",
  "reach": "Only past acquisitions",
  "leadTime": "Immediate",
  "approval": [
    "Licence terms"
  ],
  "status": "described"
}
Change-detection model · analyse
{
  "capabilityClass": "analyse",
  "resourceClass": "Change-detection model",
  "reach": "Comparable image pairs",
  "leadTime": "Minutes",
  "approval": [
    "Model licence"
  ],
  "status": "described",
  "conditions": [
    "Input imagery co-registered"
  ]
}

Validate yours against the published schema, no platform required:

curl -sO https://tilfang.com/schema/v0.1.json
npx ajv-cli validate --spec=draft2020 --strict=false -s v0.1.json -d your-declaration.json

--strict=false because the schema carries x- meta keys (version, changelog, pressure points) that validators ignore but strict mode refuses.

The artefact itself — nothing behind a download.

Raw JSON · 15.0 KB

The complete published schema, browsable in place — the very object the endpoint serves, rendered from the same source. Expand what interests you; the example catalogue is the long part.

v0.1{ 18 }
$schema: "https://json-schema.org/draft/2020-12/schema"
$id: "https://tilfang.com/schema/v0.1.json"
title: "Tilfang Capability Declaration"
description: "A capability declaration states what a resource can do, where, how soon, and who must consent — precisely enough to be found, compared and booked. Concept artefact: this describes a design, not a running system; nothing has been onboarded against it, and every example below honestly declares status "described"."
type: "object"
properties{ 10 }
$schema{ 2 }
description: "Optional: point this at the published schema URL for editor IntelliSense and self-identification."
type: "string"
capabilityClass{ 2 }
description: "Which of the seven capability classes the resource answers. The class set is closed in v0.1 — the extensibility note carries that argument."
enum[ 7 ]
0: "observe"
1: "measure"
2: "track"
3: "inspect"
4: "retrieve"
5: "analyse"
6: "report"
resourceClass{ 3 }
description: "What kind of thing provides the capability — a class of resource, never a make, model or company name (write “drone-mounted thermal camera”, not a product name). The specific unit binds at booking, not here."
type: "string"
minLength: 1
reach{ 3 }
description: "Coverage geometry: which part of a target it can actually get to. Reach is why two resources answering the same capability are not interchangeable."
type: "string"
minLength: 1
leadTime{ 3 }
description: "How soon it can deliver once booked — from “immediate” (an archive) to “weeks, by availability” (a certified inspector). A mission with a season boundary selects on this before anything else."
type: "string"
minLength: 1
approval{ 4 }
description: "Consents, clearances and standing authorisations, roughly in the order obtained. An element may name a compound consent granted as one unit; a conditional clearance states its condition. Declaring this up front is what lets a plan carry its permissions instead of discovering them mid-mission."
type: "array"
items{ 2 }
type: "string"
minLength: 1
minItems: 1
status{ 3 }
description: "Where the resource stands on the onboarding path. Defaults to “described” — which is also the honest value of every example on this site: nothing is cleared."
enum[ 6 ]
0: "described"
1: "constrained"
2: "sandboxed"
3: "cleared"
4: "monitored"
5: "revoked"
default: "described"
conditions{ 3 }
description: "Operating constraints the declaration owns up to — weather windows, daylight, co-registration, staffing. A constraint declared here is one a mission plan can check instead of trip over."
type: "array"
items{ 2 }
type: "string"
minLength: 1
extensions{ 4 }
description: "Per-domain attributes under a lowercase namespace key, carrying your real measured values, with units. Domain measures never enter the required core."
type: "object"
patternProperties{ 1 }
^[a-z][a-z0-9-]*${ 1 }
type: "object"
additionalProperties: false
declaredBy{ 4 }
description: "Who is declaring — operator name, contact, date. Optional because the comparison works anonymously; named, the declaration becomes yours to send, and to be credited for."
type: "object"
properties{ 3 }
operator{ 2 }
type: "string"
minLength: 1
contact{ 1 }
type: "string"
date{ 1 }
type: "string"
additionalProperties: false
required[ 5 ]
0: "capabilityClass"
1: "resourceClass"
2: "reach"
3: "leadTime"
4: "approval"
additionalProperties: false
examples[ 32 ]
0{ 8 }
capabilityClass: "inspect"
resourceClass: "Drone + thermal camera"
reach: "Roof and façade, close range"
leadTime: "Hours, weather permitting"
approval[ 2 ]
0: "Aviation authority"
1: "Site owner"
status: "described"
conditions[ 2 ]
0: "Daylight or a stated thermal window"
1: "Wind below the platform’s operating limit"
extensions{ 1 }
sensing{ 2 }
resolution: "Thermal ground resolution at survey distance"
threshold: "Declared against the mission’s stated defect size"
1{ 6 }
capabilityClass: "retrieve"
resourceClass: "Satellite imagery archive"
reach: "Only past acquisitions"
leadTime: "Immediate"
approval[ 1 ]
0: "Licence terms"
status: "described"
2{ 7 }
capabilityClass: "analyse"
resourceClass: "Change-detection model"
reach: "Comparable image pairs"
leadTime: "Minutes"
approval[ 1 ]
0: "Model licence"
status: "described"
conditions[ 1 ]
0: "Input imagery co-registered"
3{ 6 }
capabilityClass: "observe"
resourceClass: "Satellite payload"
reach: "Wide area, top-down only"
leadTime: "Next usable overpass"
approval[ 1 ]
0: "Tasking contract"
status: "described"
4{ 6 }
capabilityClass: "observe"
resourceClass: "Drone-mounted camera"
reach: "Any face, close range"
leadTime: "Hours, weather permitting"
approval[ 1 ]
0: "Aviation authority + site owner"
status: "described"
5{ 6 }
capabilityClass: "observe"
resourceClass: "Fixed camera"
reach: "One fixed field of view"
leadTime: "Continuous"
approval[ 1 ]
0: "Site owner"
status: "described"
6{ 6 }
capabilityClass: "observe"
resourceClass: "Shipborne radar"
reach: "Sea surface within range"
leadTime: "While the vessel is underway"
approval[ 1 ]
0: "Vessel operator"
status: "described"
7{ 6 }
capabilityClass: "observe"
resourceClass: "Commercial observation service"
reach: "Whatever the contract covers"
leadTime: "Days, per service level"
approval[ 1 ]
0: "Contract only"
status: "described"
8{ 6 }
capabilityClass: "observe"
resourceClass: "Human operator"
reach: "Wherever a person can go"
leadTime: "Scheduling and travel"
approval[ 1 ]
0: "Access permit + duty of care"
status: "described"
9{ 6 }
capabilityClass: "measure"
resourceClass: "Environmental sensor network"
reach: "Fixed points, not between them"
leadTime: "Live"
approval[ 1 ]
0: "Network owner"
status: "described"
10{ 6 }
capabilityClass: "measure"
resourceClass: "Laboratory instrument"
reach: "Only samples brought to it"
leadTime: "Days, including transport"
approval[ 1 ]
0: "Lab intake procedure"
status: "described"
11{ 6 }
capabilityClass: "measure"
resourceClass: "Weather station"
reach: "One location, standard variables"
leadTime: "Live"
approval[ 1 ]
0: "Public or operator feed"
status: "described"
12{ 6 }
capabilityClass: "measure"
resourceClass: "Multispectral payload"
reach: "The area under its path"
leadTime: "Per flight or overpass"
approval[ 1 ]
0: "Flight authorisation"
status: "described"
13{ 6 }
capabilityClass: "measure"
resourceClass: "Industrial telemetry"
reach: "Instrumented plant only"
leadTime: "Live"
approval[ 1 ]
0: "Plant owner + safety case"
status: "described"
14{ 6 }
capabilityClass: "track"
resourceClass: "Radar installation"
reach: "Within line of sight"
leadTime: "Live"
approval[ 1 ]
0: "Installation operator"
status: "described"
15{ 6 }
capabilityClass: "track"
resourceClass: "AIS data feed"
reach: "Cooperating vessels only"
leadTime: "Near real time"
approval[ 1 ]
0: "Feed subscription"
status: "described"
16{ 6 }
capabilityClass: "track"
resourceClass: "Fleet telematics feed"
reach: "One operator’s own fleet"
leadTime: "Live"
approval[ 1 ]
0: "Fleet owner + staff representation"
status: "described"
17{ 6 }
capabilityClass: "track"
resourceClass: "Sensor fusion service"
reach: "As wide as its inputs"
leadTime: "Follows its slowest input"
approval[ 1 ]
0: "Rights to every input feed"
status: "described"
18{ 6 }
capabilityClass: "inspect"
resourceClass: "Inspection robot"
reach: "Confined spaces, prepared route"
leadTime: "Days, needs mobilisation"
approval[ 1 ]
0: "Site owner + safety permit"
status: "described"
19{ 6 }
capabilityClass: "inspect"
resourceClass: "Fixed monitoring camera"
reach: "One fixed field of view"
leadTime: "Continuous"
approval[ 1 ]
0: "Site owner"
status: "described"
20{ 6 }
capabilityClass: "inspect"
resourceClass: "Certified human inspector"
reach: "Anywhere reachable on foot"
leadTime: "Weeks, by availability"
approval[ 1 ]
0: "Access permit + certification scope"
status: "described"
21{ 6 }
capabilityClass: "retrieve"
resourceClass: "Telemetry historian"
reach: "Only what was recorded"
leadTime: "Immediate"
approval[ 1 ]
0: "Data owner"
status: "described"
22{ 6 }
capabilityClass: "retrieve"
resourceClass: "Weather archive"
reach: "Station and model history"
leadTime: "Immediate"
approval[ 1 ]
0: "Open or licensed"
status: "described"
23{ 6 }
capabilityClass: "retrieve"
resourceClass: "Asset & maintenance knowledge base"
reach: "One organisation’s assets"
leadTime: "Immediate"
approval[ 1 ]
0: "Internal access rights"
status: "described"
24{ 6 }
capabilityClass: "retrieve"
resourceClass: "Public data service"
reach: "Published datasets only"
leadTime: "Immediate"
approval[ 1 ]
0: "Open licence"
status: "described"
25{ 6 }
capabilityClass: "analyse"
resourceClass: "Photogrammetry API"
reach: "Overlapping imagery sets"
leadTime: "Hours per dataset"
approval[ 1 ]
0: "Service terms"
status: "described"
26{ 6 }
capabilityClass: "analyse"
resourceClass: "Anomaly-detection service"
reach: "Signal types it was fitted to"
leadTime: "Minutes"
approval[ 1 ]
0: "Service terms"
status: "described"
27{ 6 }
capabilityClass: "analyse"
resourceClass: "Domain analyst"
reach: "Any evidence a person can read"
leadTime: "Days, by availability"
approval[ 1 ]
0: "Engagement + confidentiality"
status: "described"
28{ 6 }
capabilityClass: "report"
resourceClass: "Report generator"
reach: "Only what the plan captured"
leadTime: "Minutes"
approval[ 1 ]
0: "None beyond the mission"
status: "described"
29{ 6 }
capabilityClass: "report"
resourceClass: "Evidence store"
reach: "Artefacts and their hashes"
leadTime: "On write"
approval[ 1 ]
0: "Retention policy"
status: "described"
30{ 6 }
capabilityClass: "report"
resourceClass: "Audit-trail service"
reach: "Actions taken, not findings"
leadTime: "On write"
approval[ 1 ]
0: "Retention policy"
status: "described"
31{ 6 }
capabilityClass: "report"
resourceClass: "Human reviewer"
reach: "Judgement the others cannot give"
leadTime: "Days, by availability"
approval[ 1 ]
0: "Named signing authority"
status: "described"
x-version: "0.1.0"
x-published: "2026-08-13"
x-status: "draft-for-argument"
x-capability-classes[ 7 ]
0{ 3 }
id: "observe"
name: "Observe"
description: "Acquire imagery or signals of a target or area."
1{ 3 }
id: "measure"
name: "Measure"
description: "Quantify a physical property to a defined quality."
2{ 3 }
id: "track"
name: "Track"
description: "Follow an object or signal across time and space."
3{ 3 }
id: "inspect"
name: "Inspect"
description: "Examine an asset for condition, defects, or anomalies."
4{ 3 }
id: "retrieve"
name: "Retrieve"
description: "Access existing records, archives, or reference data."
5{ 3 }
id: "analyse"
name: "Analyse"
description: "Turn raw data into validated findings."
6{ 3 }
id: "report"
name: "Report"
description: "Produce a verifiable, provenance-rich output."
x-exclusions{ 1 }
cost: "Writing the worked examples showed cost is not a property of the resource at all: the same drone costs differently on a scheduled sweep and a call-out. Cost attaches to a booking — the (resource, mission, window) triple — so a price never appears in a capability declaration, and at concept stage a price would be a guess wearing a decimal point anyway."
x-changelog[ 1 ]
0{ 3 }
version: "0.1.0"
date: "2026-08-13"
note: "Initial publication: seven classes, five required fields (class, resource class, reach, lead time, approval), lifecycle states mirroring the onboarding gates, namespaced domain extensions, cost excluded as a booking attribute. Published as a validatable JSON Schema with the site’s full resource catalogue embedded as conformant examples."
x-pressure-points[ 3 ]
0: "A structured lead time — free text cannot be machine-compared, and the comparison claim leans on this field hardest."
1: "Jurisdiction and operating territory — reach today is geometry, not law, and a drone operator’s reality is both."
2: "Whether approval needs typed entries — a standing credential, a per-mission consent and a conditional clearance are different things an array of strings flattens."
x-feedback: "[email protected]"
x-human-readable: "https://tilfang.com/schema"

Status is part of the language.

The declaration carries where a resource stands on the onboarding path — the four gates the platform page describes, as six states a plan can check. They are definitions, not achievements: nothing on this site has passed the first gate. And certification is a lease — the last state exists so it can be used.

  1. described

    Gate 1 · Describe

    Written down as inputs, outputs and conditions — this schema’s job. Every example on this site stops here.

  2. constrained

    Gate 2 · Constrain

    Authentication, policy, cost and safety constraints recorded — before any adapter exists.

  3. sandboxed

    Gate 2 · Sandbox

    A candidate adapter has run against simulation or non-production endpoints. Nothing real touched.

  4. cleared

    Gate 3 · Clear

    A person signed one named capability scope. Anything outside it is a new onboarding.

  5. monitored

    Gate 4 · Watch

    Measured performance is compared with what was declared, continuously.

  6. revoked

    Gate 4 · Revoke

    Clearance withdrawn — certification is a lease, not a property right.

Extensible by domain, from v0.1

Some attributes are meaningful only for some classes: resolution against a stated threshold decides between a drone survey and an archive scene, and means nothing for Report. Such measures live in per-domain extension namespaces a declaration may add — never in the core, which stays the set every class can answer. The class set itself is deliberately closed at seven until an operator argues for an eighth: classes are a v0.2 argument, attributes are a per-domain extension.

"extensions": {
  "sensing": {
    "resolution": "Thermal ground resolution at survey distance",
    "threshold": "Declared against the mission’s stated defect size"
  }
}

What it deliberately leaves out

Cost. Writing the worked examples showed cost is not a property of the resource at all: the same drone costs differently on a scheduled sweep and a call-out. Cost attaches to a booking — the (resource, mission, window) triple — so a price never appears in a capability declaration, and at concept stage a price would be a guess wearing a decimal point anyway.

The ledger it keeps of itself.

  • v0.1.0 · 2026-08-13 — Initial publication: seven classes, five required fields (class, resource class, reach, lead time, approval), lifecycle states mirroring the onboarding gates, namespaced domain extensions, cost excluded as a booking attribute. Published as a validatable JSON Schema with the site’s full resource catalogue embedded as conformant examples.

Known v0.2 pressure points, named before anyone argues them:

  • A structured lead time — free text cannot be machine-compared, and the comparison claim leans on this field hardest.
  • Jurisdiction and operating territory — reach today is geometry, not law, and a drone operator’s reality is both.
  • Whether approval needs typed entries — a standing credential, a per-mission consent and a conditional clearance are different things an array of strings flattens.

The three answers worth more than praise.

This schema is published ahead of any product, deliberately. The test it runs is simple: an operator either describes a real asset in it — or tells us where it breaks. Any of those answers moves the concept further than a private draft ever could.

  1. Describe one real asset you operate in this schema. Where did a required field refuse your reality?

  2. Which attribute does your domain compare on that neither the core nor an extension namespace can carry?

  3. Which consent in your actual approval chain has no place in the approval array as defined?