Definition schema
Every key in definition.json (types, fields, identity, merge, links, setting filters, views, learning, inbox), what lint refuses, and the shape of the compiled meta/definition. Taken from definition.py.
definition.json declares what a routine records and how the Desk shows it. definition.py lints it and compiles one or more definitions into the meta/definition document the Desk and the write step read. See Definition for the concept.
Top level
| Key | Type | Required | Meaning |
|---|---|---|---|
version |
integer | yes | 1 or more. Raise it when the definition changes |
label |
text | no | The producer’s label on the Desk. Falls back to the routine name |
inbox |
bool | no | The producer writes Inbox messages. Then max_inbox_per_run must be a number setting |
types |
object | yes | Record types, keyed by type name |
views |
list | no | Views shipped with the routine |
learning |
object | no | Learning block. Absent means learning is off |
Types
A type name is lowercase letters and digits with single hyphens (^[a-z][a-z0-9]*(-[a-z0-9]+)*$).
| Key | Type | Required | Meaning |
|---|---|---|---|
label |
text | no | Singular label |
plural |
text | no | Plural label |
identity |
text | yes | domain, name or field:<field> |
merge |
text | no | merge (default) or separate |
fields |
object | yes | At least one field |
links |
list | no | Type names this type links to. Each must be declared |
settingFilters |
list | no | {setting, field} pairs |
Identity rules
| Rule | Key |
|---|---|
field:<name> |
The value of that field, for example field:url for a role |
domain |
The record’s key, else values.domain, else values.name. A value that is not a domain once normalised uses the name rule |
name |
The normalised name |
The entity id is <type>--<slug(key)>. Slugs are lowercase [a-z0-9-], at most 120 characters, with a SHA-1 suffix for longer keys. Two keys that slug the same fail the plan with both named. With merge policy separate, the id is <type>--<slug(producerId--key)>.
Fields
| Key | Type | Required | Meaning |
|---|---|---|---|
type |
text | yes | text, number, date, url, choice, list, bool |
label |
text | no | Shown on the Desk |
summary |
bool | no | Shown in summaries |
choices |
list | choice only | Non-empty |
Setting filters
"settingFilters": [{"setting": "title_keywords", "field": "title"}]
The setting must be declared in routine.toml, be a list, and have a role of include or exclude. The field must be declared on the type. Text fields match case-insensitive substrings; other types match whole values, case-insensitive for strings. A filtered record is kept with status: "dropped" and a dropReason such as not in title_keywords.
Views
| Key | Type | Values |
|---|---|---|
id |
text | ^[a-z0-9][a-z0-9-]*$ |
type |
text | A declared type |
name |
text | Shown on the Desk |
filters |
object | q, status, starred, tag, source, reason, fields |
filters.status |
text | all, active, dropped |
filters.fields |
object | {field: value}, the one value a declared field must equal |
window |
text | all, week, month, last-month |
sort |
object | {field, dir}, dir asc or desc |
group |
text | A field name |
columns |
list | Field names |
Besides declared fields, a view may name the meta fields lastSeen, firstSeen, seenCount, status and dropReason. A field filter at the top level of filters is an error. Views that people save and views the agent proposes use the same shape. See Views.
Learning
| Key | Default | Range |
|---|---|---|
enabled |
required | bool |
signals |
all on | {signal: bool}; signals override, uncaptured_term, dead_item, source_health, limit_pressure, connections, edit_drift, manual_repetition |
limits |
[] |
max_inbox_per_run, declared as a number setting |
minSample |
5 | at least 1 |
minEffect |
0.6 | above 0, at most 1 |
cooldownDays |
14 | at least 0 |
maxPerRun |
3 | 0 to 10 |
deadAfterRuns |
10 | at least 2 |
Since 0.5.0: a ninth signal,
people_drop.
Example: Hiring Signals
From templates/jobs-watch/definition.json, fields shortened:
{
"version": 1,
"label": "Jobs watch",
"inbox": true,
"types": {
"company": {
"label": "Company", "plural": "Companies",
"identity": "domain", "merge": "merge",
"fields": {"name": {"label": "Name", "type": "text", "summary": true},
"domain": {"label": "Domain", "type": "url", "summary": true}},
"settingFilters": [{"setting": "excluded_companies", "field": "domain"}]
},
"role": {
"label": "Role", "plural": "Roles",
"identity": "field:url", "merge": "merge",
"links": ["company"],
"fields": {"title": {"label": "Title", "type": "text", "summary": true},
"market": {"label": "Market", "type": "choice", "choices": ["AU", "US", "CA", "NZ", "PH", "GB", "DE"], "summary": true},
"url": {"label": "URL", "type": "url"}},
"settingFilters": [{"setting": "markets", "field": "market"},
{"setting": "title_keywords", "field": "title"},
{"setting": "excluded_companies", "field": "company_domain"}]
}
},
"views": [
{"id": "new-roles", "type": "role", "name": "New roles", "filters": {"status": "active"},
"sort": {"field": "firstSeen", "dir": "desc"}, "columns": ["title", "company", "market", "posted"]}
],
"learning": {"enabled": true}
}
The full role type also has company, company_domain, location, remote, salary_max, posted, seniority and summary. The template ships two more views, dropped-roles and hiring-companies.
What lint checks
versionis a whole number of 1 or more;typesis a non-empty object.- Each type: a valid name, at least one field, known field types, a
choiceslist on choice fields, a valid identity rule naming a declared field, a known merge policy, links to declared types. - Each setting filter names a declared list setting with a role, and a declared field.
- Each view passes the view rules above.
- The learning block has only known keys, known signals and in-range numbers, and
limitsnames declared number settings it can tune. - No never-learnable setting (a name containing push, gate, send, alert, permission, budget, maxruns or capoverride, ignoring case and separators) is bound while learning is on.
inbox: trueneeds a number settingmax_inbox_per_run.
Each problem prints as FAIL definition.json: <problem>.
The compiled meta/definition
compile merges every producer’s definition into one document with the keys producers, schema, types, version and views. Each entry in producers carries the producer’s id, label, schedule, definitionVersion, inbox, its type names, its settings schema, and its learning config with every default filled in. version is a short hash of the compiled content, printed by compile (for example eda3cea96ab1). A compiled document over 256 KiB is refused.