Skip to main content
Glama

ShotPulled

Server Details

Espresso dialing: log a shot, say how it tasted, get one change in your grinder's own clicks.

If you are the author of this connector, you can claim ownership by verifying the domain or GitHub account it belongs to. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Uptime
99.8% over 45 days
Last Tested
Transport
Streamable HTTP ยท MCP 2025-06-18
URL

TDQS

A3.7/5.0

Scored across 44 tools

Disambiguation4/5

Each tool targets a distinct resource+action, and the descriptions explicitly carve boundaries (e.g. diagnose_shot vs diagnose_preview, log_shot vs update_shot, register_coffee vs register_bag). Only mild overlap remains among the read-side helpers (get_dial_state, get_stats, suggest_next_step), which are still separable but could occasionally be confused.

Naming Consistency4/5

Names overwhelmingly follow a predictable snake_case verb_noun pattern (list_*, get_*, register_*, update_*, set_*, log_*, delete_*). A few entries break the pattern by being noun-only (grinder_math, kb_changelog), a minor deviation from an otherwise uniform scheme.

Tool Count3/5

44 tools is heavy and reflects repeated register/list/update families across many entity types (beans, bags, grinders, machines, scales, waters, recipes, shots). The breadth of the domain justifies much of it, but the surface is large enough to burden an agent's selection.

Completeness4/5

Coverage is very broad: full lifecycle for beans, bags, grinders, machines, scales, waters, shots, maintenance, and the knowledge base, including diagnosis and calibration. Minor gaps exist (programs can be registered but not updated/deleted or listed; several entities are archived rather than deleted), which agents can work around.

Available Tools

44 tools
compute_ageCompute coffee age
Read-onlyIdempotent
Inspect

Compute a bag's age in days off roast and its resting/staling verdict, for the coffee's current bag by default or for the bag named.

ParametersJSON Schema
NameRequiredDescriptionDefault
bag_idNoA bag of that coffee (from list_beans' bags[]); null = its current bag
bean_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
bag_idYes
bean_idYes
verdictYes
age_daysYes
warningsYes
roast_dateYes
rest_windowYes
verdict_codeYes
days_off_roastYes
grams_remainingYes
days_since_openedYes
effective_age_daysYes
frozen_days_excludedYes
delete_shotDelete a shot
DestructiveIdempotent
Inspect

Delete a logged shot from history. Restores the bean's remaining weight (which is derived from logged doses). Hard delete: there is no undo. To fix a mistake on an otherwise-valid shot, prefer update_shot over delete-and-relog.

ParametersJSON Schema
NameRequiredDescriptionDefault
shot_idYesID of the shot to delete

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
deleted_shot_idYes
diagnose_previewPreview a diagnosis
Read-onlyIdempotent
Inspect

Sandbox-only diagnosis, writes nothing (no verdict, no recommendation-trail entry). Two modes: pass shot_id to dry-run a LOGGED shot (optionally overriding its sensory_tags, for the "what would this read as?" preview; the shot's own bean and its age at pulled_at are used), or pass the full metric set (bean_id, grinder_id, machine_id, grind_label, dose_g, yield_g, time_s, source) for a hypothetical shot. Identical output shape to diagnose_shot, including bean_context.

ParametersJSON Schema
NameRequiredDescriptionDefault
dose_gNoDose in grams
sourceNoGrinder position source. Affects G1 warning (raw mode only)
time_sNoExtraction time in seconds
bean_idNoCoffee bean ID (must belong to this account)
shot_idNoPreview a logged shot by ID (dry-run; ignores the metric params below)
yield_gNoYield in grams
grinder_idNoGrinder ID (must belong to this account)
machine_idNoMachine ID (must belong to this account)
grind_labelNoGrinder setting label, e.g. "1.1.3"
sensory_tagsNoSensory observations, e.g. ["sour","bitter"]. With shot_id: replaces the stored tags for this preview (omit to use stored; [] = none).

Output Schema

ParametersJSON Schema
NameRequiredDescription
factsYes
categoryYes
warningsYes
hypothesesYes
kb_versionYes
bean_contextYes
warning_codesYes
one_variable_onlyYes
diagnose_shotDiagnose a shot
Read-onlyIdempotent
Inspect

Evaluate shot metrics to provide ranked hypotheses (C6) and warn on flip-flops (G2) or fatigue (G6). Resolves the SHOT's own bean (age computed at the shot's pulled_at), never the active profile, and echoes it as bean_context, so diagnosing an older or differently-filed shot is always safe. The engine reads metrics and sensory tags, NOT free-text notes, so make sure taste feedback is recorded as sensory_tags on the shot (via log_shot or update_shot) before diagnosing; otherwise an in-range shot that tastes bad will come back "balanced".

ParametersJSON Schema
NameRequiredDescriptionDefault
shot_idNoOptional shot ID; defaults to last pulled shot.

Output Schema

ParametersJSON Schema
NameRequiredDescription
factsYes
categoryYes
warningsYes
hypothesesYes
kb_versionYes
bean_contextYes
warning_codesYes
one_variable_onlyYes
get_dial_stateGet current dial state
Read-onlyIdempotent
Inspect

Retrieve current dialing state, active context, recent shots, recommendations, and locked recipes.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
recent_shotsYes
active_coffeeYes
locked_recipeYes
active_grinderYes
active_machineYes
active_programYes
maintenance_summaryYes
recent_recommendationsYes
get_kb_versionGet knowledge base versionA
Read-onlyIdempotent
Inspect

Retrieve the current version of the knowledge base.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
kb_versionYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so the safety profile is fully covered. The description adds no extra behavioral context beyond the basic retrieval action, but it does not contradict the annotations either. Given the low bar enabled by rich annotations, a neutral score of 3 is appropriate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence that states the exact operation and target. There is no redundant or filler content, and the key information is front-loaded. It earns its place by being perfectly compact and informative at a basic level.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity, an output schema exists to define the return value, and annotations cover the operational behavior, nothing critical is missing from the description. It could have added a hint about what 'knowledge base version' refers to, but for a zero-parameter read-only getter, the description is sufficiently complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there is no parameter information to explain. Per the rubric, a 0-parameter tool gets a baseline of 4; the description does not need to compensate for any schema gaps because there are no parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'Retrieve' and identifies the resource as 'the current version of the knowledge base,' making the tool's purpose immediately clear. It does not differentiate itself from siblings, but no sibling appears to handle the same operation, so the lack of explicit distinction is not a significant gap.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The usage context is implied by the name and description: an agent would naturally use this to get the knowledge base version. However, the description gives no explicit guidance about when to prefer this over related tools like kb_changelog or get_stats, nor any conditions under which it should not be used.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_maintenance_guidesGet maintenance guides
Read-onlyIdempotent
Inspect

Step-by-step maintenance guides: tools, supplies, steps and warnings, in our own words with the maker's documents as sources. With no arguments, every guide for the user's current grinders and machines (and the water filter fitted in each). With guide_ids, those guides; the ids come from maintenance.tasks[].guide.id in list_grinders and list_machines. Ids that match no guide are listed under missing.

ParametersJSON Schema
NameRequiredDescriptionDefault
guide_idsNoOptional: the guides to fetch. Omit for every guide the user's equipment can use

Output Schema

ParametersJSON Schema
NameRequiredDescription
guidesYes
missingYes
catalog_versionYes
get_ruleGet a dialing ruleA
Read-onlyIdempotent
Inspect

Retrieve the detailed text of a specific rule from the knowledge base by its rule ID.

ParametersJSON Schema
NameRequiredDescriptionDefault
rule_idYesThe ID of the rule to fetch, e.g. CAT.DARK

Output Schema

ParametersJSON Schema
NameRequiredDescription
textYes
rule_idYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds minor behavioral context by promising 'detailed text' as the return content, but does not disclose error/not-found behavior. No contradiction exists.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with no filler; the core operation, resource, and identifier are stated immediately. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple, idempotent, read-only lookup with one fully documented parameter and an output schema, the description provides sufficient context. It does not explain what kinds of rules exist or where rule IDs originate, but those are not necessary for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter rule_id is fully described in the input schema (100% coverage), including an example value 'CAT.DARK'. The description only reinforces that lookup is by rule ID, adding no significant meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description identifies a specific action ('Retrieve the detailed text'), a specific resource ('a specific rule from the knowledge base'), and the lookup key ('by its rule ID'). It is clear, though it does not explicitly distinguish itself from sibling getters such as get_dial_state or get_kb_version.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage: when you have a rule ID and need the rule text. However, it provides no explicit guidance on when not to use this tool or which sibling tool to prefer for related lookups.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_statsGet statisticsA
Read-onlyIdempotent
Inspect

Get compact flat usage stats for a grinder, machine, or bean.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesThe entity ID
scopeYesThe stats scope

Output Schema

ParametersJSON Schema
NameRequiredDescription
brewsYes
last_beanNo
last_usedNo
grams_groundNo
effective_ageNo
beans_consumedNo
grams_consumedNo
grams_remainingNo
last_grind_settingNo

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds that stats are 'compact flat', which hints at the output shape, but it does not disclose aggregation details, time range, or any other behavioral nuances beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, compact sentence that front-loads the essential information. Every word contributes: the action, the output type, and the supported scopes.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter read-only tool with an output schema and comprehensive annotations, the description is complete enough. The schema covers parameters, annotations cover behavior, and the output schema covers return structure, leaving no critical gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters fully. The description adds minimal parameter meaning beyond echoing the scope enum ('grinder', 'machine', 'bean') and the notion of usage stats, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the action ('Get'), the resource type ('usage stats'), and the supported scopes ('grinder, machine, or bean'). This distinguishes it from sibling getters like get_dial_state and get_rule, which target different kinds of information.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool: when you need usage statistics for one of the three entity types. However, it does not explicitly contrast with alternatives or state when not to use it, such as when listing entities or retrieving state information.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

grinder_mathGrinder mathB
Read-onlyIdempotent
Inspect

Determine steps/clicks difference and directions between setting labels (C3).

ParametersJSON Schema
NameRequiredDescriptionDefault
to_labelYes
from_labelYes
grinder_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
stepsYes
directionYes
step_unitYes
burr_gap_travel_micronsYes
relative_coarseness_noteYes

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, and the description's 'Determine' is consistent with a safe computation. It adds that the result is a steps/clicks difference and direction, but does not reveal additional behavioral nuance such as label assumptions or failure behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence with no filler, and the key operation is front-loaded. The unexplained 'C3' parenthetical costs it a top score because it is cryptic rather than clarifying.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only math utility with an output schema, the high-level purpose is enough for selection, but the agent must guess the labeling convention and why grinder_id is required. Combined with no usage routing, the definition is workable but not fully self-sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description must carry the meaning, but it only loosely connects from_label/to_label as 'setting labels' and never explains the label syntax or the grinder_id parameter. It also doesn't state the mapping between labels and steps/clicks, which is the core semantic the agent needs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly identifies a calculation: it determines the difference/direction in steps/clicks between two setting labels, so an agent knows what the tool computes. It does not explicitly distinguish itself from siblings like set_grinder_position, and the parenthetical 'C3' is unexplained.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides no guidance on when to call this rather than a sibling such as set_grinder_position or suggest_next_step. It neither states prerequisites (e.g., a registered grinder) nor when the math should be used, so an agent must infer from context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

kb_changelogKnowledge base changelogA
Read-onlyIdempotent
Inspect

Retrieve the changelog showing updates and version differences for the knowledge base.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
changelogYes

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description is consistent with the annotations (readOnlyHint=true, idempotentHint=true, destructiveHint=false). It adds mild context by specifying the changelog content (updates and version differences), but it does not describe ordering, scope, or any additional behavioral detail. Given the annotations already cover safety, this is adequate but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One clear sentence with no filler. The main action and content are front-loaded, and every word adds meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple, parameterless read-only tool with rich annotations and an output schema present, the description is sufficient. An agent can correctly infer what the tool returns and that invoking it is safe and non-mutating.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there is no parameter semantics to explain. The baseline of 4 applies here. The schema coverage is 100% trivially, and the description does not need to compensate for undocumented parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Retrieve') and resource ('changelog') and clarifies what it contains ('updates and version differences for the knowledge base'). It distinguishes from the sibling get_kb_version by indicating full version history rather than the current version.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The intended use is reasonably clear from the description: retrieve knowledge-base changelog/history. However, it does not explicitly mention when to use this tool over get_kb_version or other knowledge-related tools, nor does it state any exclusions. The usage context is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_beansList coffees
Read-onlyIdempotent
Inspect

List the coffees registered for the account, with status filter. Each coffee carries its bags[] (every purchase, with its own freshness and grams left) and current_bag_id; the row's top-level roast_date, state, grams_remaining and age fields are the current bag's. The id on each row is the number this account knows that coffee by, counting from 1: safe to show, and what other tools expect back; bag ids are a separate series.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoFilter by status: current, archived, or all. Defaults to current.

Output Schema

ParametersJSON Schema
NameRequiredDescription
beansYes
list_grindersList grinders
Read-onlyIdempotent
Inspect

List grinders registered for the account, with status filter. The id on each row is the number this account knows that record by, counting from 1: safe to show, and what other tools expect back. Each row carries its maintenance block: every task with its class (S schedule, H habit, Y symptom, A the machine signals it, T technician, N never, U unstated, E event), due state, and the guide to follow.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoFilter by status: current, archived, or all. Defaults to current.
maintenanceNoHow much of each row's maintenance block to include. compact (default): every task with its class, due state, schedule and guide. full: also the maker's own words (quote, source, alternates, the interval as written).

Output Schema

ParametersJSON Schema
NameRequiredDescription
grindersYes
list_machinesList espresso machines
Read-onlyIdempotent
Inspect

List machines registered for the account, with status filter. The id on each row is the number this account knows that record by, counting from 1: safe to show, and what other tools expect back. Each row carries its maintenance block, researched per model: every task with its class, due state, what the maker forbids, and the guide to follow. settings lists the selectors its model has and where each stands (null: unknown model, or none).

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoFilter by status: current, archived, or all. Defaults to current.
maintenanceNoHow much of each row's maintenance block to include. compact (default): every task with its class, due state, schedule and guide. full: also the maker's own words (quote, source, alternates, the interval as written).

Output Schema

ParametersJSON Schema
NameRequiredDescription
machinesYes
list_maintenance_dueList maintenance due
Read-onlyIdempotent
Inspect

What maintenance is due across the user's current grinders and machines, most urgent first. Use it for "is anything due?". Only tasks with an interval compete: a task the machine counts and signals itself, one done by habit or when a symptom shows, and one the maker advises against never appear. Each item says how far along it is (ratio, done of every, on which basis), whether it is coming up (soon), and whether the interval is the user's, the maker's or ShotPulled's default.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNodue (default): due or overdue, and not muted. all: every scheduled task, muted ones last

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
computed_atYes
catalog_versionYes
list_recipesList locked recipes
Read-onlyIdempotent
Inspect

List recipes (all or filtered by equipment and status). The id on each row is the number this account knows that record by, counting from 1: safe to show, and what other tools expect back.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoFilter by status: current, archived, or all. Defaults to current.
bean_idNo
grinder_idNo
machine_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
recipesYes
list_scalesList scales
Read-onlyIdempotent
Inspect

List registered scales for the account. The id on each row is the number this account knows that record by, counting from 1: safe to show, and what other tools expect back.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoFilter by status: current (unarchived), archived, or all. Defaults to current.

Output Schema

ParametersJSON Schema
NameRequiredDescription
scalesYes
list_shotsList shots
Read-onlyIdempotent
Inspect

List shot history with support for pagination and filtering. Every shot carries a derived taste_pending flag (1 = logged with no sensory tags, no rating, and no tasted flip: the tasting is still owed and can be backfilled with update_shot).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoNumber of records to return (1-500)
offsetNoOffset for pagination
filtersNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
shotsYes
totalYes
list_watersList water recipes
Read-onlyIdempotent
Inspect

List registered waters for the account. The id on each row is the number this account knows that record by, counting from 1: safe to show, and what other tools expect back.

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoFilter by status: current (unarchived), archived, or all. Defaults to current.

Output Schema

ParametersJSON Schema
NameRequiredDescription
watersYes
lock_recipeLock a recipeA
DestructiveIdempotent
Inspect

Lock a successful shot as the reference dialing recipe for this equipment profile. It overwrites the recipe already locked for the same coffee, grinder, machine, program and drink intent, which keeps its recipe_id.

ParametersJSON Schema
NameRequiredDescriptionDefault
drink_intentYes
from_shot_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
recipe_idYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds the critical specifics beyond that: it overwrites only the recipe matching the same coffee/grinder/machine/program/drink-intent tuple, and preserves the existing recipe_id. That explains exactly what is destroyed and how identity is retained, which the annotations alone cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler, and the definition of the action is front-loaded before the overwrite rule. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description needn't explain return values, and the annotations cover the safety profile. It covers the mutation effect well; only minor gaps remain, such as failure behavior or why drink_intent (straight/milk) is a required selector.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema coverage the description must carry the load, and it does: it frames from_shot_id as the 'successful shot' source and names the composite key (coffee, grinder, machine, program, drink intent) that determines which record drink_intent selects. This meaningfully exceeds the bare enum/integer schema, though from_shot_id's exact semantics remain only implied.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (lock) and resource (recipe) and defines what locking means: promoting a successful shot to the reference dialing recipe for the equipment profile. This clearly separates it from list_recipes, update_shot, or log_shot.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'Lock a successful shot' implies you should have a successful shot to promote, which is implied usage context. However, it never states when-not to use it or points to any alternative (e.g., list_recipes or update_shot), leaving the routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

log_maintenanceLog maintenanceInspect

Log a cleaning or maintenance job against a piece of equipment. A task that takes the thing apart opens a calibration epoch, and every recipe locked before it is read through that epoch's offset. Record the offset here if you counted the clicks while reassembling, which is the one moment anybody actually knows it. Any task in the maintenance vocabulary can be logged against a grinder or machine it belongs to, including one the maker advises against, because the log records what was done. Read each piece of equipment's tasks, their intervals and their due state from list_grinders and list_machines.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNoOptional: what you did, and anything that surprised you
taskYesWhich maintenance job was performed
detailsNoFields specific to this task. Which ones a task takes is published as details_fields on each task; a burr clean takes none
evidenceNoOne line recording what the measurement rested on, e.g. "Counted 6 clicks coarser at reassembly."
guide_idNoOptional: the id of the maintenance guide that was followed. Must be a guide for this task
equipment_idYesThe ID of that piece of equipment
offset_valueNoThe correction, if you measured it now: clicks to ADD to a pre-clean reading to get the same grind today, signed along the collar's own number direction. Omit it and the epoch stays unmeasured, which is a state the app shows rather than a zero it assumes
performed_atNoWhen it was done (ISO 8601 or YYYY-MM-DD HH:MM:SS, UTC). Defaults to now; backdating is fine
disturbs_zeroNoWhether this job disturbed the reference the stored numbers are read against: for a burr clean, whether the burrs actually came out. Defaults to the task's own answer; send 0 for a wipe-down that left the collar alone
offset_sourceNoHow the offset was arrived at: pull (a reference shot), counted (clicks counted at reassembly), typed (asserted directly)
equipment_kindYesWhich kind of equipment this job was done on

Output Schema

ParametersJSON Schema
NameRequiredDescription
entryYes
dedupedYes
messageYes
entry_idYes
log_recommendationLog a recommendationCInspect

Log a recommended dialing change to allow contradiction/oscillation checking (G2).

ParametersJSON Schema
NameRequiredDescriptionDefault
leverYes
directionYes
rationaleYes
confidenceYes
cited_rulesNo
based_on_shotNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes

TDQS

C2.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already carry the mutation and non-idempotency signals, so the description's job is lighter. It adds context that this records a recommendation rather than a definitive change and notes the G2 analysis purpose, but says nothing about repeated logging effects or return behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one tight sentence with no filler, and the key action is front-loaded. The parenthetical G2 is opaque but does not add bloat.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a six-parameter write tool with four required fields and no schema descriptions, this single sentence is too sparse. The purpose is clear, but the agent still lacks guidance on how to fill parameters, especially cited_rules and based_on_shot, and when this tool should be preferred over siblings.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description only hints at a 'dialing change,' which loosely covers lever and direction. It does not explain confidence, cited_rules, or based_on_shot, and does not compensate for the schema's lack of parameter documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verbโ€”logโ€”and a distinct object, a recommended dialing change, which separates it from sibling log tools like log_shot and log_maintenance. It does not explicitly name an alternative, so it stops short of full differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a purpose ('to allow contradiction/oscillation checking') but no explicit when-to-use or when-not-to-use guidance. It does not point to any alternative tools or exclusions, leaving the agent to infer when logging is appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

log_shotLog a shotInspect

Log an espresso or alternative shot/brew attempt. Uses the active context (bean/grinder/machine/program) unless overridden via bean_id/grinder_id/machine_id/program_id. ALWAYS pass bean_id explicitly when the user names a specific coffee, so the shot cannot land on the wrong bag. Backdate with pulled_at when the shot happened earlier. When the user reports taste (bitter, sour, harsh, hollowโ€ฆ), include matching sensory_tags: the diagnosis engine reads tags and metrics, not free-text flavor_notes. When the user tasted the shot and reports it as GOOD/clean (no defects), pass tasted=1 with no sensory_tags. Otherwise a tag-less, rating-less shot is filed taste-pending as if never tasted.

ParametersJSON Schema
NameRequiredDescriptionDefault
tdsNoTotal Dissolved Solids percentage (e.g. 9.1 or 1.35)
bag_idNoWhich bag of the coffee the shot came from; defaults to its current (open) bag. Bag numbers are on list_beans' bags[]
dose_gYes
ratingNo
tastedNo1 = the shot was tasted at log time. The explicit way to record a CLEAN tasting: sensory tags all describe defects, so a good shot has none. Without this flag (or a rating) it would be filed taste-pending. Tags or a rating also mark a shot as tasted; 0 (default) = taste later.
time_sYes
bean_idNoOverride: log against this bean instead of the active one (null = active)
verdictNo
yield_gYes
water_idNoOptional references to waters formulation
best_brewNo1 if marked as best brew, 0 otherwise
favouriteNo1 if favourite, 0 otherwise
pulled_atNoWhen the shot was actually pulled (ISO 8601 or "YYYY-MM-DD HH:MM:SS"), for backdated entries. Defaults to now (null = now). When backdating, pass the returned shot_id to diagnose_shot explicitly, because the default diagnosis target is the chronologically latest shot.
beverage_gNoYield mass excluding cup/vessel weight in grams
grinder_idNoOverride: grinder used, if not the active one (null = active)
machine_idNoOverride: machine used, if not the active one (null = active)
program_idNoOverride: machine program used, if not the active one (null = active)
temp_tasteNo
vessel_nameNoCup/vessel name
bloom_time_sNoPre-wetting or bloom duration in seconds
drink_intentNo
flavor_notesNo
flow_profileNoOpaque flow profile data (JSON/TEXT)
method_toolsNoJSON representation of method tools used (e.g., paper filters, screen)
observationsNo
sensory_tagsNo
finish_actionYes
temperature_cNoBrew temperature in Celsius
data_confidenceNomeasured = weighed/timed live; recalled = from memory; estimated = a best guess (e.g. "~25s" after missing the timer)
vessel_weight_gNoCup/vessel weight in grams
machine_settingsNoOnly when this one shot was pulled with a selector somewhere other than the machine's recorded settings: {key: position}. The shot is otherwise stamped with those automatically; a lasting change goes through update_machine.
pressure_profileNoPressure profile description or values
first_drip_time_sNoTime to first drip in seconds

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
shot_idYes
merge_beansMerge two coffees
Destructive
Inspect

Fold one coffee into another when the same coffee was registered twice. Every bag, shot, recipe and recommendation of from_bean_id moves to into_bean_id; the active coffee follows if it was the one merged away; origins move only if the target has none. Where both hold a locked recipe for the same grinder, machine, program and drink, the newer lock wins and the older is deleted. The source coffee is archived, never deleted. Irreversible: confirm both numbers with the user first (list_beans shows them).

ParametersJSON Schema
NameRequiredDescriptionDefault
reasonNoOptional note, recorded on the surviving coffee's notes with the merge
from_bean_idYesThe duplicate: the coffee number that will be emptied and archived
into_bean_idYesThe coffee number that keeps everything

Output Schema

ParametersJSON Schema
NameRequiredDescription
movedYes
statusYes
messageYes
into_bean_idYes
active_followedYes
replaced_recipesYes
register_bagRegister a bagInspect

Register another bag of a coffee that is already in list_beans: the same roaster's product, bought again. It keeps the coffee's recipes, notes and history; only the purchase facts (roast date, weight, price, state) are new. Does not change the active coffee. Returns a bag_id: bag numbers are their own series, separate from bean numbers. For a coffee that is not in list_beans yet, call register_coffee instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
eanNo
costNo
stateNoDefaults to sealed; the first log_shot against it opens it
bean_idYesThis account's own coffee number, from list_beans. Never guess one.
qr_codeNo
storageNo
buy_dateNoCalendar day in YYYY-MM-DD format: a day, not a timestamp
currencyNo
bag_notesNoNotes about THIS bag (a batch note, where it was bought). The coffee's own description lives on the coffee, in notes.
product_idNoSet by the apps. Leave out.
roast_dateYesCalendar day in YYYY-MM-DD format: a day, not a timestamp
opened_dateNoCalendar day in YYYY-MM-DD format: a day, not a timestamp
bag_weight_gNoBag weight in grams
best_by_dateNoCalendar day in YYYY-MM-DD format: a day, not a timestamp
lot_revision_idNoSet by the apps. Leave out.
catalog_coffee_idNoSet by the apps. Leave out.

Output Schema

ParametersJSON Schema
NameRequiredDescription
bag_idYes
statusYes
bean_idYes
messageYes
register_coffeeRegister a coffeeInspect

Register a coffee that is NOT yet in list_beans, together with its first bag. It does not switch a coffee in use: it becomes active only when no coffee is in use (none active, or the active one archived or with every bag finished); otherwise call set_active with its bean_id when the user starts brewing it. The active field of the reply says which. The coffee is the roaster's product (roaster, origins, variety, process, roast level, roasting type, cupping score, aromatics, roaster notes, rest window); the bag is this purchase (roast date, weight, price, state). For another bag of a coffee already on file call register_bag instead: it keeps the recipes and notes. Returns bean_id and the first bag's bag_id.

ParametersJSON Schema
NameRequiredDescriptionDefault
eanNo
urlNo
bodyNoFree text; roasters usually say low, medium or high
costNo
nameYes
notesNoThe coffee's own description: the roaster's tasting notes, the dialing approach that worked. Per bag notes go in bag_notes.
stateNo
originNo
ratingNo
acidityNoFree text; roasters usually say low, medium or high
co2e_kgNo
originsNoList of bean origin details
qr_codeNo
roasterNo
storageNo
varietyNo
archivedNo1 if archived, 0 otherwise
bean_mixNoE.g. blend details
buy_dateNoCalendar day in YYYY-MM-DD format: a day, not a timestamp
currencyNo
finishedNo1 if finished, 0 otherwise
aromaticsNo
bag_notesNo
favouriteNo1 if favourite, 0 otherwise
frozen_atNoCalendar day the bag went into the freezer, YYYY-MM-DD: a day, not a timestamp
sweetnessNoFree text; roasters usually say low, medium or high
product_idNoSet by the apps. Leave out.
roast_dateYesCalendar day in YYYY-MM-DD format: a day, not a timestamp
arabica_pctNoPercent arabica, 100 for a pure arabica; the rest robusta
attachmentsNoJSON or comma-separated list of attachments
frozen_noteNo
opened_dateNoCalendar day in YYYY-MM-DD format: a day, not a timestamp
roast_levelYes
roast_rangeNo
unfrozen_atNoCalendar day the bag came out, YYYY-MM-DD: a day, not a timestamp
bag_weight_gNoBag weight in grams
best_by_dateNoCalendar day in YYYY-MM-DD format: a day, not a timestamp
process_typeYes
roast_customNo
decaffeinatedNo1 if decaf, 0 if regular
dial_categoryNoDialing behavior class: classic = medium/traditional espresso roasts (chocolate/nut, balanced); dark = genuinely dark/roasty; the light categories cover Nordic and ultra-light styles.
roasting_typeNo
cupping_pointsNo
frozen_storageNo
lot_revision_idNoSet by the apps. Leave out.
catalog_coffee_idNoSet by the apps. Leave out.
rest_window_days_maxNo
rest_window_days_minNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
activeYes
bag_idYes
statusYes
bean_idYes
messageYes
register_grinderRegister a grinderInspect

Register a manual or electric grinder with its dial settings scheme. It becomes the active grinder only when no grinder is in use (none active, or the active one archived); otherwise call set_active with its grinder_id to switch to it. The active field of the reply says which.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesThe name/model of the grinder, e.g. Kinu M47
notesNoAdditional notes
photoNoPhoto path or URL
archivedNo1 if archived, 0 if active
burr_typeYes
max_valueNoOptional travel max bounds
min_valueNoOptional travel min bounds
catalog_idNoOptional: the maintenance catalog model this is (the `id` of a catalog row, e.g. rancilio-silvia), when it was registered from the catalog. Its maintenance then comes from that model's researched record. "none" says it is not in the catalog.
motor_typeYes
nominal_stepYesSmallest adjustment increment (e.g. 1 click or 0.1collar units)
setting_schemeYesCollar mark style: single clicks or compound (rotation.number.clicks)
components_specNoJSON mapping string representing compound adjustment math
microns_per_stepNoOptional mechanical burr travel microns per nominal step
direction_conventionYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
activeYes
statusYes
messageYes
grinder_idYes
register_machineRegister an espresso machineInspect

Register an espresso or alternative preparation machine. It becomes the active machine only when no machine is in use (none active, or the active one archived); otherwise call set_active with its machine_id to switch to it. The active field of the reply says which.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesMachine name/model, e.g. Dedica EC685
notesNo
photoNoPhoto path or URL
toolsNoJSON or comma-separated tools, e.g., paper filters, flow control, metal mesh
archivedNo1 if archived, 0 if active
prep_typeNoPreparation equipment type. One of: espresso_machine, lever_press, moka_pot, aeropress, french_press, v60_dripper, cold_brew. Lower snake_case.
catalog_idNoOptional: the maintenance catalog model this is (the `id` of a catalog row, e.g. rancilio-silvia), when it was registered from the catalog. Its maintenance then comes from that model's researched record. "none" says it is not in the catalog.
prep_styleNoPreparation style. One of: espresso, filter, immersion, percolation. Only "espresso" is diagnosed by the dialing engine (G8). Anything else is recorded but never dialed, so do not guess this field.
boiler_typeNo
hardness_dhNoOptional: the TOTAL hardness (GH) of the water this machine runs on, in ยฐdH (German degrees; ppm as CaCO3 รท 17.85), as a test strip reports it. Picks the band of a maker's hardness table for descaling and filter life
control_typeYes
connected_deviceNoMetadata mapping to smart hardware APIs
basket_size_gramsNo
built_in_grinder_idNoid of a grinder built into this machine (bean-to-cup / integrated grinder)

Output Schema

ParametersJSON Schema
NameRequiredDescription
activeYes
statusYes
messageYes
machine_idYes
register_programRegister a machine programA
Destructive
Inspect

Register a programmed shot button on a machine. A program cuts the shot off either by weight (program_type "volumetric", set target_volume_g) or by time (program_type "timed", set target_time_s). One machine can have a mix of both. A program_number the machine already has is overwritten with these settings; shots logged on it keep pointing at it.

ParametersJSON Schema
NameRequiredDescriptionDefault
machine_idYes
descriptionNo
program_typeNoCutoff method: "volumetric" (weight) or "timed" (duration). Defaults to volumetric.
target_time_sNoTarget shot duration cutoff in seconds (required for timed programs)
volume_sourceNoConfidence in the stored cutoff value, for either type
program_numberYesProgram number / button index (e.g. 1 or 2)
target_volume_gNoTarget yield cutoff in grams (required for volumetric programs)

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
program_idYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and openWorldHint=false, so the mutation profile is known. The description usefully adds what actually gets destroyed: an existing program_number is overwritten while previously logged shots keep pointing at it, which is valuable context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the core action and then the type semantics and overwrite consequence. Every sentence carries information, though it could be slightly terser.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists so return values need not be explained, and the description covers the two program types and overwrite behavior well. The omission of volume_source semantics and any error/permission notes keeps it from being fully complete for a 7-parameter mutation tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 71%, and the description reinforces the key pairing (program_type "volumetric" โ†’ target_volume_g, "timed" โ†’ target_time_s), adding the relational logic the schema states per-field. However it says nothing about volume_source, description, or machine_id, so it only partially compensates for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Register a programmed shot button on a machine") and immediately defines what a program is and how it terminates a shot. This clearly distinguishes it from sibling registration tools like register_machine or register_grinder, which target different resources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description distinguishes the two program modes (volumetric vs timed) and the fields each requires, which implies usage, but it never says when to call this versus update_machine or register_machine, nor any prerequisites. Usage is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

register_scaleRegister a scaleInspect

Register a brewing scale: the instrument that weighs the dose and the yield.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesScale name/model, e.g. Acaia Lunar, Timemore Black Mirror Basic 2
notesNoAdditional notes
powerNoHow it is powered or recharged
depth_mmNoPlatform depth in mm
width_mmNoPlatform width in mm. Measure your drip tray
auto_tareNo1 if it zeroes itself when a vessel is set down, 0 if not, null if unstated
height_mmNoOverall height in mm: the dimension that decides whether it fits under a group head
auto_timerNo1 if the timer starts on first flow, 0 if not, null if unstated
capacity_gNoMaximum weight in grams. The cup or portafilter counts against it
scale_typeYesWhat the scale is built for: espresso (drip-tray footprint), brew (pour-over platform), dual (both modes), connected (app/controller integration), dosing (gravimetric dispensing), training, bench (high capacity, coarse)
connectivityNoHow the scale talks to an app or a machine controller
resolution_gNoFinest published readability in grams. Leave null unless the maker states it
water_resistanceNoIEC 60529 ingress code as published, e.g. IPX4, IPX6, IP67, or none
flow_rate_displayNo1 if the scale shows live flow rate in g/s, 0 if it does not, null if the maker never said
resolution_bandedNo1 when resolution_g only holds in the lowest weight band and coarsens with load. Put the ladder in notes

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
scale_idYes
register_waterRegister a water recipeBInspect

Register a custom or commercial water formulation.

ParametersJSON Schema
NameRequiredDescriptionDefault
ghNoGeneral hardness (GH) in ppm
khNoKarbonate hardness (KH) in ppm
tdsNoTDS in ppm
nameYesWater formulation name, e.g. Lotus Light & Bright, Third Wave Water
typeNoType, e.g., mineralized, tap, distilled, RO
notesNoAdditional notes
sodiumNoSodium concentration in ppm
calciumNoCalcium concentration in ppm
magnesiumNoMagnesium concentration in ppm

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
water_idYes

TDQS

B3.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already signal that this is not a read-only operation, but the description adds no behavioral detail beyond that, such as whether duplicate names overwrite, whether registration requires approval, or any side effects. It does not contradict the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no filler, front-loading the core action and resource. It is appropriately sized for the simplicity of the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a registration tool, the description combined with full schema coverage, annotations, and an output schema provides enough context for an agent to select and invoke the tool. It is slightly incomplete only because it omits usage guidance relative to sibling tools, but that is covered under usage_guidelines.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% property description coverage, so the schema carries the parameter documentation burden. The description adds no additional parameter meaning beyond what is already in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'Register' with the resource 'water formulation', which matches the title and clearly identifies the tool's purpose. It also distinguishes this tool from sibling register_* tools by naming water as the entity, and custom/commercial scope adds useful clarity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no guidance on when to use this tool over alternatives such as list_waters or update_* tools. No exclusions, prerequisites, or comparison with sibling tools are provided; usage context is only implied by the name and title.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_activeSet active equipmentA
Idempotent
Inspect

Switch the active bean, grinder or machine for this account. The numbers come from list_beans, list_grinders and list_machines. Registering a coffee, grinder or machine makes it active only when nothing of that kind is in use (the active field of the reply says which), so call this to start using something new as well as to switch back.

ParametersJSON Schema
NameRequiredDescriptionDefault
bean_idNoThis account's own bean number, as returned by list_beans. Never guess one; null = leave unchanged
grinder_idNoThis account's own grinder number, as returned by list_grinders. Never guess one; null = leave unchanged
machine_idNoThis account's own machine number, as returned by list_machines. Never guess one; null = leave unchanged
program_idNoA program number from the active machine's list; switching machines clears it. null = leave unchanged

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare idempotentHint=true and destructiveHint=false, so the safety profile is partly covered. The description adds useful behavioral context beyond them: partial updates leave fields unchanged (matching the null parameters) and the reply's `active` field reports what actually got activated, which is genuine non-obvious behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the core action, then provenance, then the non-obvious activation caveat. Dense and mostly waste-free, though the final sentence is slightly long for what it conveys.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return-value docs aren't needed, and the description still hints at the reply's `active` field. Combined with full schema coverage and annotations, an agent has what it needs; only the absence of explicit alternative routing keeps it from a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, and each parameter already documents 'null = leave unchanged' and 'Never guess one'. The description only adds the provenance of the numbers (list_beans/list_grinders/list_machines), which largely duplicates the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('switch the active') and resource (bean, grinder, machine) for this account, and explicitly sets it apart from the register_* siblings by noting that registration only activates when nothing of that kind is in use. An agent can tell this is the explicit activation setter, not a create/update tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for when to call it: to start using something new (after registering) as well as to switch back to an existing item. It also points to the list_* tools that supply valid numbers, but doesn't enumerate alternatives such as update_bean or set_grinder_position for other forms of change.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_equipment_archivedArchive or restore equipmentA
Idempotent
Inspect

Archive or restore a grinder, machine, water, or scale.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesThe ID of the equipment
kindYesThe kind of equipment to archive/restore
archivedYes1 to archive, 0 to restore

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate a non-read-only, non-destructive, idempotent operation. The description adds the useful behavioral nuance that the operation can both archive and restore, implying reversibility, but it does not disclose side effects, permissions, or what happens to equipment once archived.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence: action first, then the complete resource scope. Every word carries information, with no redundant filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple three-parameter tool with fully documented schema fields, enum constraints, safety annotations, and an output schema, the description provides sufficient context for correct invocation. Remaining details such as return format are already handled elsewhere.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and each parameter already has a clear description, including enum values for kind and archived. The description only restates the equipment kinds from the schema and adds no new parameter-level meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses precise verbs ('Archive or restore') and explicitly names all supported resource kinds ('grinder, machine, water, or scale'), matching the kind enum exactly. This makes the tool's purpose immediately distinguishable from siblings like set_active or register_*.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context: use this tool when you need to archive or restore one of the listed equipment types. It does not name alternatives or explicit when-not scenarios, but the action is unique among the sibling tools, so no routing conflict exists.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_grinder_positionSet grinder positionA
DestructiveIdempotent
Inspect

Set the current grinder collar position. source="measured" resets verification freshness. It replaces the stored position; no history of earlier positions is kept.

ParametersJSON Schema
NameRequiredDescriptionDefault
sourceYesWhether setting is verified ("measured") or guess ("recalled"/"assumed")
grinder_idYes
setting_labelYesVerbatim display label, e.g. "1.1.2"

Output Schema

ParametersJSON Schema
NameRequiredDescription
sourceYes
statusYes
messageYes
grinder_idYes
setting_labelYes
position_valueYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true; the description adds real value by explaining what 'destructive' means here โ€” the stored position is replaced and no history is retained โ€” plus the side effect of a measured source on verification freshness. It stops short of describing permissions or the response shape.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core action, then the consequence of the source value, then the overwrite behavior. No filler, every sentence carries information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists so return values need no explanation, and the description covers the destructive overwrite semantics and the key source side effect. It is nearly complete for a 3-parameter mutation tool, with only minor gaps around permissions and freshness semantics.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%, with source and setting_label documented in the schema. The description adds meaning to source="measured" by tying it to verification freshness, which the schema does not state, but it says nothing about grinder_id and only partially compensates for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource โ€” setting the grinder collar position โ€” which separates it from the generic update_grinder sibling. It does not explicitly name or contrast with alternatives, but the scope is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit 'use when / don't use when' guidance or named alternative, but the note that source="measured" resets verification freshness implies when a verified entry is warranted versus a guess. Usage is inferable rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_maintenance_offsetSet calibration offset
DestructiveIdempotent
Inspect

Record how far a maintenance job moved the reference, on an entry that opened a calibration epoch. Takes an ENTRY, not a piece of equipment: the offset belongs to the event that caused it, which is what lets several of them compose for a recipe locked before all of them. Zero is a legitimate measurement and means "measured, and it had not moved". Omit offset_value entirely to clear it back to unmeasured.

ParametersJSON Schema
NameRequiredDescriptionDefault
sourceNoHow it was arrived at: pull, counted, or typed
entry_idYesThe maintenance entry that opened the epoch, from list_grinders
evidenceNoOne line recording what it rested on, e.g. "Reference pull 1.38 g/s against 1.74 g/s locked."
offset_valueNoClicks to ADD to a pre-clean reading to get the same grind today, signed along the collar's own number direction. 0 records "unchanged"; omit to clear the measurement

Output Schema

ParametersJSON Schema
NameRequiredDescription
entryYes
messageYes
set_maintenance_scheduleSet a maintenance schedule
DestructiveIdempotent
Inspect

Set the user's own schedule for one maintenance task on one grinder or machine: their own interval, switching it off, or muting the reminder until a date. Only the keys you send in fields change; send every: null to go back to the maker's guidance and muted_until: null to unmute. Use it when the user states how often they do a task or asks to be left alone about one, never to invent an interval. The task's class, interval and due state are read back from list_grinders and list_machines.

ParametersJSON Schema
NameRequiredDescriptionDefault
taskYesThe task, as its value in that equipment's maintenance.tasks
fieldsNo
changed_atNoOptional: when the user made this change (ISO 8601, UTC). An app sending a queued edit passes it, so an older edit never overwrites a newer one; it is then answered with applied: false
equipment_idYesThis account's own grinder or machine number, from list_grinders or list_machines
equipment_kindYesWhich kind of equipment the task is on

Output Schema

ParametersJSON Schema
NameRequiredDescription
dueYes
taskYes
classYes
everyYes
appliedYes
messageYes
scheduleYes
equipment_idYes
every_sourceYes
equipment_kindYes
suggest_next_stepSuggest the next step
Read-onlyIdempotent
Inspect

Retrieve the single next experiment step from the reasoning engine.

ParametersJSON Schema
NameRequiredDescriptionDefault
bean_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
categoryYes
warningsYes
next_stepYes
warning_codesYes
update_bagUpdate a bag
Destructive
Inspect

Change bag-level facts on one bag of a coffee: open, seal, freeze, thaw or finish it, correct its roast date, weight, grams left or price. Bag numbers come from the bags[] on list_beans (or current_bag_id). For the coffee itself (roaster, origin, roast level, rest window, notes), use update_bean.

ParametersJSON Schema
NameRequiredDescriptionDefault
bag_idYesThis account's own bag number, from list_beans' bags[]. Never guess one.
fieldsYes
reasonNoOptional free-text note, appended to this bag's notes as an ordinary line. Omit it and nothing is written.

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
update_beanUpdate a coffee
Destructive
Inspect

Update a coffee's own fields (roaster, origins, roast level, rest window, notes, ratingโ€ฆ). Bag-shaped fields sent here (state, roast_date, bag_weight_g, grams_remaining, costโ€ฆ) land on the coffee's CURRENT bag. Use update_bag when it has more than one. Changing dial_category changes what the engine advises (G5, C10), so say why in the optional note.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsYes
reasonNoOptional free-text note, appended as an ordinary line to the coffee's notes, or to the current bag's bag_notes when the call changed only bag fields. Omit it and nothing is written.
bean_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
update_grinderUpdate a grinder
Destructive
Inspect

Correct a registered grinder: its name, burrs, collar scheme, nominal step, layout, range or notes. Only the keys you send in fields change; send null to clear an optional field (an empty string also clears a text field, but not a number or a closed list). Required fields can be changed but not cleared. fields may be omitted when only reason is sent. setting_scheme, nominal_step and components_spec describe the collar every recorded grind label is read through: call with dry_run first to see which recorded settings would read as a different position, and tell the user before saving. Saving records the change in the grinder's maintenance history; when a locked recipe's setting moves it also opens an unmeasured calibration epoch (set_maintenance_offset resolves it). The collar's current setting is marked assumed when it reads differently, or cleared when the new collar cannot read it, and measured offsets are converted when a click changes worth. Changing direction_convention is a correction: it moves no number, but every finer/coarser said about this grinder was the wrong way round.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsNo
reasonNoOptional note, appended to this record's own notes as an ordinary line. Omit it and nothing is written.
dry_runNotrue: write nothing, and answer with what the edit would do to the settings already recorded (moved[], checked, epoch, position_moved, position_cleared, rescaled_offsets, resigned_offsets, step_ignored, direction_flipped, recipe_count)
grinder_idYesThis account's own grinder number, from list_grinders. Never guess one.

Output Schema

ParametersJSON Schema
NameRequiredDescription
epochYes
movedYes
statusYes
checkedYes
dry_runYes
messageYes
entry_idYes
grinder_idYes
unreadableYes
moved_countYes
changed_keysYes
recipe_countYes
step_ignoredYes
reads_changedYes
position_movedYes
untranslatableYes
position_clearedYes
rescaled_offsetsYes
resigned_offsetsYes
direction_flippedYes
untranslatable_recipesYes
update_machineUpdate a machine
Destructive
Inspect

Correct a registered machine (its name, control type, prep type and style, basket, boiler, accessories or notes), or record where its selectors stand (settings). Only the keys you send in fields change; send null to clear an optional field (an empty string also clears a text field, but not a number or a closed list). Required fields can be changed but not cleared. fields may be omitted when only reason is sent. prep_style decides whether shots on this machine are diagnosed at all: only "espresso" is. Programs are edited with register_program, the built-in grinder link is not editable here, and archiving is set_equipment_archived.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsNo
reasonNoOptional note, appended to this record's own notes as an ordinary line. Omit it and nothing is written.
machine_idYesThis account's own machine number, from list_machines. Never guess one.

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
machine_idYes
changed_keysYes
update_scaleUpdate a scale
Destructive
Inspect

Correct a registered scale: its type, resolution, capacity, capabilities, build or notes. Only the keys you send in fields change; send null to clear an optional field (an empty string also clears a text field, but not a number or a closed list). Required fields can be changed but not cleared. fields may be omitted when only reason is sent. The three capabilities are 1, 0, or null for "the maker never said"; leave one out rather than sending 0 when nobody knows.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsNo
reasonNoOptional note, appended to this record's own notes as an ordinary line. Omit it and nothing is written.
scale_idYesThis account's own scale number, from list_scales. Never guess one.

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
scale_idYes
changed_keysYes
update_shotUpdate a shot
DestructiveIdempotent
Inspect

Correct fields on an already-logged shot in place, with no need to delete and re-log. Use for fixing a wrong dose/yield/time or grind label, re-filing a shot onto the right bean (bean_id), backfilling rating/tasting notes, or fixing the timestamp (pulled_at). Changing grind_label re-derives the numeric grind position from the shot's grinder; changing yield/time/dose/tds keeps flow rate and extraction yield consistent automatically.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsYesOnly the fields to change
shot_idYesID of the shot to correct

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
shot_idYes
updated_fieldsYes
update_waterUpdate a water recipe
Destructive
Inspect

Correct a registered water: its name, type, mineral figures or notes. Only the keys you send in fields change; send null to clear an optional field (an empty string also clears a text field, but not a number or a closed list). Required fields can be changed but not cleared. fields may be omitted when only reason is sent.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsNo
reasonNoOptional note, appended to this record's own notes as an ordinary line. Omit it and nothing is written.
water_idYesThis account's own water number, from list_waters. Never guess one.

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
water_idYes
changed_keysYes

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 21 tool updates
    • Changedcompute_age2 fields changed
      • addedOutput schema / properties / verdict_code
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "bean_id",
        -  "bag_id",
        -  "roast_date",
        -  "age_days",
        -  "days_off_roast",
        -  "days_since_opened",
        -  "frozen_days_excluded",
        -  "effective_age_days",
        -  "rest_window",
        -  "verdict",
        -  "grams_remaining",
        -  "warnings"
        -]New value: +[
        +  "bean_id",
        +  "bag_id",
        +  "roast_date",
        +  "age_days",
        +  "days_off_roast",
        +  "days_since_opened",
        +  "frozen_days_excluded",
        +  "effective_age_days",
        +  "rest_window",
        +  "verdict",
        +  "verdict_code",
        +  "grams_remaining",
        +  "warnings"
        +]
    • Changeddiagnose_preview3 fields changed
      • changedInput schema / properties / source / description
        Previous value: -"Grinder position source โ€” affects G1 warning (raw mode only)"New value: +"Grinder position source. Affects G1 warning (raw mode only)"
      • addedOutput schema / properties / warning_codes
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "category",
        -  "facts",
        -  "hypotheses",
        -  "warnings",
        -  "one_variable_only",
        -  "kb_version",
        -  "bean_context"
        -]New value: +[
        +  "category",
        +  "facts",
        +  "hypotheses",
        +  "warnings",
        +  "one_variable_only",
        +  "kb_version",
        +  "warning_codes",
        +  "bean_context"
        +]
    • Changeddiagnose_shot2 fields changed
      • addedOutput schema / properties / warning_codes
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "category",
        -  "facts",
        -  "hypotheses",
        -  "warnings",
        -  "one_variable_only",
        -  "kb_version",
        -  "bean_context"
        -]New value: +[
        +  "category",
        +  "facts",
        +  "hypotheses",
        +  "warnings",
        +  "one_variable_only",
        +  "kb_version",
        +  "warning_codes",
        +  "bean_context"
        +]
    • Changedget_dial_state10 fields changed
      • addedOutput schema / properties / active_coffee / properties / age_verdict_code
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / active_coffee / properties / bag / properties / age_verdict_code
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / active_coffee / properties / bag / properties / lot_revision_id
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / active_coffee / properties / bag / properties / product_id
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / active_coffee / properties / bag / required
        Previous value: -[
        -  "id",
        -  "bean_id",
        -  "roast_date",
        -  "buy_date",
        -  "opened_date",
        -  "best_by_date",
        -  "bag_weight_g",
        -  "weight_adjustment_g",
        -  "cost",
        -  "currency",
        -  "state",
        -  "finished",
        -  "frozen_at",
        -  "unfrozen_at",
        -  "frozen_storage",
        -  "frozen_note",
        -  "storage",
        -  "ean",
        -  "qr_code",
        -  "bag_notes",
        -  "archived",
        -  "days_off_roast",
        -  "days_since_opened",
        -  "frozen_days_excluded",
        -  "effective_age_days",
        -  "age_verdict",
        -  "grams_remaining"
        -]New value: +[
        +  "id",
        +  "bean_id",
        +  "roast_date",
        +  "buy_date",
        +  "opened_date",
        +  "best_by_date",
        +  "bag_weight_g",
        +  "weight_adjustment_g",
        +  "cost",
        +  "currency",
        +  "state",
        +  "finished",
        +  "frozen_at",
        +  "unfrozen_at",
        +  "frozen_storage",
        +  "frozen_note",
        +  "storage",
        +  "ean",
        +  "qr_code",
        +  "bag_notes",
        +  "archived",
        +  "product_id",
        +  "lot_revision_id",
        +  "days_off_roast",
        +  "days_since_opened",
        +  "frozen_days_excluded",
        +  "effective_age_days",
        +  "age_verdict",
        +  "age_verdict_code",
        +  "grams_remaining"
        +]
      • addedOutput schema / properties / active_coffee / properties / catalog_coffee_id
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / active_coffee / properties / roaster / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / active_coffee / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "roaster",
        -  "origin",
        -  "variety",
        -  "roast_date",
        -  "roast_level",
        -  "process_type",
        -  "dial_category",
        -  "bag_notes",
        -  "rest_window_days_min",
        -  "rest_window_days_max",
        -  "state",
        -  "opened_date",
        -  "storage",
        -  "is_active",
        -  "weight_adjustment_g",
        -  "buy_date",
        -  "bag_weight_g",
        -  "cost",
        -  "currency",
        -  "decaffeinated",
        -  "bean_mix",
        -  "roast_range",
        -  "roast_custom",
        -  "roasting_type",
        -  "aromatics",
        -  "cupping_points",
        -  "rating",
        -  "favourite",
        -  "url",
        -  "ean",
        -  "qr_code",
        -  "co2e_kg",
        -  "attachments",
        -  "archived",
        -  "frozen_at",
        -  "unfrozen_at",
        -  "frozen_storage",
        -  "frozen_note",
        -  "best_by_date",
        -  "finished",
        -  "notes",
        -  "arabica_pct",
        -  "body",
        -  "acidity",
        -  "sweetness",
        -  "age_days",
        -  "days_off_roast",
        -  "days_since_opened",
        -  "frozen_days_excluded",
        -  "effective_age_days",
        -  "age_verdict",
        -  "grams_remaining",
        -  "current_bag_id",
        -  "bag"
        -]New value: +[
        +  "id",
        +  "name",
        +  "roaster",
        +  "origin",
        +  "variety",
        +  "roast_date",
        +  "roast_level",
        +  "process_type",
        +  "dial_category",
        +  "bag_notes",
        +  "rest_window_days_min",
        +  "rest_window_days_max",
        +  "state",
        +  "opened_date",
        +  "storage",
        +  "is_active",
        +  "weight_adjustment_g",
        +  "buy_date",
        +  "bag_weight_g",
        +  "cost",
        +  "currency",
        +  "decaffeinated",
        +  "bean_mix",
        +  "roast_range",
        +  "roast_custom",
        +  "roasting_type",
        +  "aromatics",
        +  "cupping_points",
        +  "rating",
        +  "favourite",
        +  "url",
        +  "ean",
        +  "qr_code",
        +  "co2e_kg",
        +  "attachments",
        +  "archived",
        +  "frozen_at",
        +  "unfrozen_at",
        +  "frozen_storage",
        +  "frozen_note",
        +  "best_by_date",
        +  "finished",
        +  "notes",
        +  "arabica_pct",
        +  "body",
        +  "acidity",
        +  "sweetness",
        +  "catalog_coffee_id",
        +  "age_days",
        +  "days_off_roast",
        +  "days_since_opened",
        +  "frozen_days_excluded",
        +  "effective_age_days",
        +  "age_verdict",
        +  "age_verdict_code",
        +  "grams_remaining",
        +  "current_bag_id",
        +  "bag"
        +]
      • addedOutput schema / properties / active_machine / properties / prep_style / type
        Added value: +"string"
      • addedOutput schema / properties / active_machine / properties / prep_type / type
        Added value: +"string"
    • Changedget_maintenance_guides1 field changed
      • changedInput schema / properties / guide_ids / description
        Previous value: -"Optional โ€” the guides to fetch. Omit for every guide the user's equipment can use"New value: +"Optional: the guides to fetch. Omit for every guide the user's equipment can use"
    • Changedlist_beans10 fields changed
      • addedOutput schema / properties / beans / items / properties / age_verdict_code
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / beans / items / properties / bags / items / properties / age_verdict_code
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / beans / items / properties / bags / items / properties / lot_revision_id
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / beans / items / properties / bags / items / properties / product_id
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / beans / items / properties / bags / items / required
        Previous value: -[
        -  "id",
        -  "bean_id",
        -  "roast_date",
        -  "buy_date",
        -  "opened_date",
        -  "best_by_date",
        -  "bag_weight_g",
        -  "weight_adjustment_g",
        -  "cost",
        -  "currency",
        -  "state",
        -  "finished",
        -  "frozen_at",
        -  "unfrozen_at",
        -  "frozen_storage",
        -  "frozen_note",
        -  "storage",
        -  "ean",
        -  "qr_code",
        -  "bag_notes",
        -  "archived",
        -  "effective_age_days",
        -  "age_verdict",
        -  "grams_remaining",
        -  "days_since_opened",
        -  "days_off_roast",
        -  "frozen_days_excluded"
        -]New value: +[
        +  "id",
        +  "bean_id",
        +  "roast_date",
        +  "buy_date",
        +  "opened_date",
        +  "best_by_date",
        +  "bag_weight_g",
        +  "weight_adjustment_g",
        +  "cost",
        +  "currency",
        +  "state",
        +  "finished",
        +  "frozen_at",
        +  "unfrozen_at",
        +  "frozen_storage",
        +  "frozen_note",
        +  "storage",
        +  "ean",
        +  "qr_code",
        +  "bag_notes",
        +  "archived",
        +  "product_id",
        +  "lot_revision_id",
        +  "effective_age_days",
        +  "age_verdict",
        +  "age_verdict_code",
        +  "grams_remaining",
        +  "days_since_opened",
        +  "days_off_roast",
        +  "frozen_days_excluded"
        +]
      • addedOutput schema / properties / beans / items / properties / catalog_coffee_id
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / beans / items / properties / origins / items / properties / country_code
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / beans / items / properties / origins / items / required
        Previous value: -[
        -  "country",
        -  "region",
        -  "farm",
        -  "farmer",
        -  "variety",
        -  "processing",
        -  "elevation_m",
        -  "elevation_max_m",
        -  "harvest",
        -  "percentage"
        -]New value: +[
        +  "country",
        +  "country_code",
        +  "region",
        +  "farm",
        +  "farmer",
        +  "variety",
        +  "processing",
        +  "elevation_m",
        +  "elevation_max_m",
        +  "harvest",
        +  "percentage"
        +]
      • changedOutput schema / properties / beans / items / properties / roaster / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / beans / items / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "roaster",
        -  "roast_level",
        -  "archived",
        -  "favourite",
        -  "decaffeinated",
        -  "process_type",
        -  "dial_category",
        -  "rest_window_days_min",
        -  "rest_window_days_max",
        -  "rating",
        -  "aromatics",
        -  "cupping_points",
        -  "roasting_type",
        -  "variety",
        -  "origin",
        -  "url",
        -  "notes",
        -  "arabica_pct",
        -  "body",
        -  "acidity",
        -  "sweetness",
        -  "roast_date",
        -  "buy_date",
        -  "opened_date",
        -  "best_by_date",
        -  "bag_weight_g",
        -  "weight_adjustment_g",
        -  "cost",
        -  "currency",
        -  "state",
        -  "finished",
        -  "frozen_at",
        -  "unfrozen_at",
        -  "frozen_storage",
        -  "frozen_note",
        -  "storage",
        -  "ean",
        -  "qr_code",
        -  "bag_notes",
        -  "effective_age_days",
        -  "age_verdict",
        -  "grams_remaining",
        -  "days_since_opened",
        -  "days_off_roast",
        -  "frozen_days_excluded",
        -  "current_bag_id",
        -  "bags",
        -  "origins"
        -]New value: +[
        +  "id",
        +  "name",
        +  "roaster",
        +  "catalog_coffee_id",
        +  "roast_level",
        +  "archived",
        +  "favourite",
        +  "decaffeinated",
        +  "process_type",
        +  "dial_category",
        +  "rest_window_days_min",
        +  "rest_window_days_max",
        +  "rating",
        +  "aromatics",
        +  "cupping_points",
        +  "roasting_type",
        +  "variety",
        +  "origin",
        +  "url",
        +  "notes",
        +  "arabica_pct",
        +  "body",
        +  "acidity",
        +  "sweetness",
        +  "roast_date",
        +  "buy_date",
        +  "opened_date",
        +  "best_by_date",
        +  "bag_weight_g",
        +  "weight_adjustment_g",
        +  "cost",
        +  "currency",
        +  "state",
        +  "finished",
        +  "frozen_at",
        +  "unfrozen_at",
        +  "frozen_storage",
        +  "frozen_note",
        +  "storage",
        +  "ean",
        +  "qr_code",
        +  "bag_notes",
        +  "effective_age_days",
        +  "age_verdict",
        +  "age_verdict_code",
        +  "grams_remaining",
        +  "days_since_opened",
        +  "days_off_roast",
        +  "frozen_days_excluded",
        +  "current_bag_id",
        +  "bags",
        +  "origins"
        +]
    • Changedlist_grinders1 field changed
      • changedInput schema / properties / maintenance / description
        Previous value: -"How much of each row's maintenance block to include. compact (default): every task with its class, due state, schedule and guide. full: also the maker's own words โ€” quote, source, alternates, the interval as written."New value: +"How much of each row's maintenance block to include. compact (default): every task with its class, due state, schedule and guide. full: also the maker's own words (quote, source, alternates, the interval as written)."
    • Changedlist_machines3 fields changed
      • changedInput schema / properties / maintenance / description
        Previous value: -"How much of each row's maintenance block to include. compact (default): every task with its class, due state, schedule and guide. full: also the maker's own words โ€” quote, source, alternates, the interval as written."New value: +"How much of each row's maintenance block to include. compact (default): every task with its class, due state, schedule and guide. full: also the maker's own words (quote, source, alternates, the interval as written)."
      • changedOutput schema / properties / machines / items / properties / prep_style / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
      • changedOutput schema / properties / machines / items / properties / prep_type / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +"string"
    • Changedlist_recipes1 field changed
      • changedOutput schema / properties / recipes / items / properties / roaster_name / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
    • Changedlog_maintenance3 fields changed
      • changedInput schema / properties / disturbs_zero / description
        Previous value: -"Whether this job disturbed the reference the stored numbers are read against โ€” for a burr clean, whether the burrs actually came out. Defaults to the task's own answer; send 0 for a wipe-down that left the collar alone"New value: +"Whether this job disturbed the reference the stored numbers are read against: for a burr clean, whether the burrs actually came out. Defaults to the task's own answer; send 0 for a wipe-down that left the collar alone"
      • changedInput schema / properties / guide_id / description
        Previous value: -"Optional โ€” the id of the maintenance guide that was followed. Must be a guide for this task"New value: +"Optional: the id of the maintenance guide that was followed. Must be a guide for this task"
      • changedInput schema / properties / note / description
        Previous value: -"Optional โ€” what you did, and anything that surprised you"New value: +"Optional: what you did, and anything that surprised you"
    • Changedlog_shot3 fields changed
      • changedInput schema / properties / data_confidence / description
        Previous value: -"measured = weighed/timed live; recalled = from memory; estimated = a best guess (e.g. missed the timer โ€” \"~25s\")"New value: +"measured = weighed/timed live; recalled = from memory; estimated = a best guess (e.g. \"~25s\" after missing the timer)"
      • changedInput schema / properties / pulled_at / description
        Previous value: -"When the shot was actually pulled (ISO 8601 or \"YYYY-MM-DD HH:MM:SS\"), for backdated entries. Defaults to now (null = now). When backdating, pass the returned shot_id to diagnose_shot explicitly โ€” the default diagnosis target is the chronologically latest shot."New value: +"When the shot was actually pulled (ISO 8601 or \"YYYY-MM-DD HH:MM:SS\"), for backdated entries. Defaults to now (null = now). When backdating, pass the returned shot_id to diagnose_shot explicitly, because the default diagnosis target is the chronologically latest shot."
      • changedInput schema / properties / tasted / description
        Previous value: -"1 = the shot was tasted at log time. The explicit way to record a CLEAN tasting: sensory tags all describe defects, so a good shot has none โ€” without this flag (or a rating) it would be filed taste-pending. Tags or a rating also mark a shot as tasted; 0 (default) = taste later."New value: +"1 = the shot was tasted at log time. The explicit way to record a CLEAN tasting: sensory tags all describe defects, so a good shot has none. Without this flag (or a rating) it would be filed taste-pending. Tags or a rating also mark a shot as tasted; 0 (default) = taste later."
    • Changedregister_bag7 fields changed
      • changedInput schema / properties / best_by_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / buy_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • addedInput schema / properties / catalog_coffee_id
        Added value: +{
        +  "description": "Set by the apps. Leave out.",
        +  "type": "string"
        +}
      • addedInput schema / properties / lot_revision_id
        Added value: +{
        +  "description": "Set by the apps. Leave out.",
        +  "type": "string"
        +}
      • changedInput schema / properties / opened_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • addedInput schema / properties / product_id
        Added value: +{
        +  "description": "Set by the apps. Leave out.",
        +  "type": "string"
        +}
      • changedInput schema / properties / roast_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
    • Changedregister_coffee10 fields changed
      • changedInput schema / properties / best_by_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / buy_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • addedInput schema / properties / catalog_coffee_id
        Added value: +{
        +  "description": "Set by the apps. Leave out.",
        +  "type": "string"
        +}
      • changedInput schema / properties / frozen_at / description
        Previous value: -"Calendar day the bag went into the freezer, YYYY-MM-DD โ€” a day, not a timestamp"New value: +"Calendar day the bag went into the freezer, YYYY-MM-DD: a day, not a timestamp"
      • addedInput schema / properties / lot_revision_id
        Added value: +{
        +  "description": "Set by the apps. Leave out.",
        +  "type": "string"
        +}
      • changedInput schema / properties / notes / description
        Previous value: -"The coffee's own description โ€” the roaster's tasting notes, the dialing approach that worked. Per bag notes go in bag_notes."New value: +"The coffee's own description: the roaster's tasting notes, the dialing approach that worked. Per bag notes go in bag_notes."
      • changedInput schema / properties / opened_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • addedInput schema / properties / product_id
        Added value: +{
        +  "description": "Set by the apps. Leave out.",
        +  "type": "string"
        +}
      • changedInput schema / properties / roast_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / unfrozen_at / description
        Previous value: -"Calendar day the bag came out, YYYY-MM-DD โ€” a day, not a timestamp"New value: +"Calendar day the bag came out, YYYY-MM-DD: a day, not a timestamp"
    • Changedregister_grinder1 field changed
      • changedInput schema / properties / catalog_id / description
        Previous value: -"Optional โ€” the maintenance catalog model this is (the `id` of a catalog row, e.g. rancilio-silvia), when it was registered from the catalog. Its maintenance then comes from that model's researched record. \"none\" says it is not in the catalog."New value: +"Optional: the maintenance catalog model this is (the `id` of a catalog row, e.g. rancilio-silvia), when it was registered from the catalog. Its maintenance then comes from that model's researched record. \"none\" says it is not in the catalog."
    • Changedregister_machine3 fields changed
      • changedInput schema / properties / catalog_id / description
        Previous value: -"Optional โ€” the maintenance catalog model this is (the `id` of a catalog row, e.g. rancilio-silvia), when it was registered from the catalog. Its maintenance then comes from that model's researched record. \"none\" says it is not in the catalog."New value: +"Optional: the maintenance catalog model this is (the `id` of a catalog row, e.g. rancilio-silvia), when it was registered from the catalog. Its maintenance then comes from that model's researched record. \"none\" says it is not in the catalog."
      • changedInput schema / properties / hardness_dh / description
        Previous value: -"Optional โ€” the TOTAL hardness (GH) of the water this machine runs on, in ยฐdH (German degrees; ppm as CaCO3 รท 17.85), as a test strip reports it. Picks the band of a maker's hardness table for descaling and filter life"New value: +"Optional: the TOTAL hardness (GH) of the water this machine runs on, in ยฐdH (German degrees; ppm as CaCO3 รท 17.85), as a test strip reports it. Picks the band of a maker's hardness table for descaling and filter life"
      • changedInput schema / properties / prep_style / description
        Previous value: -"Preparation style. One of: espresso, filter, immersion, percolation. Only \"espresso\" is diagnosed by the dialing engine (G8) โ€” anything else is recorded but never dialed, so do not guess this field."New value: +"Preparation style. One of: espresso, filter, immersion, percolation. Only \"espresso\" is diagnosed by the dialing engine (G8). Anything else is recorded but never dialed, so do not guess this field."
    • Changedregister_scale3 fields changed
      • changedInput schema / properties / height_mm / description
        Previous value: -"Overall height in mm โ€” the dimension that decides whether it fits under a group head"New value: +"Overall height in mm: the dimension that decides whether it fits under a group head"
      • changedInput schema / properties / resolution_banded / description
        Previous value: -"1 when resolution_g only holds in the lowest weight band and coarsens with load โ€” put the ladder in notes"New value: +"1 when resolution_g only holds in the lowest weight band and coarsens with load. Put the ladder in notes"
      • changedInput schema / properties / width_mm / description
        Previous value: -"Platform width in mm โ€” measure your drip tray"New value: +"Platform width in mm. Measure your drip tray"
    • Changedset_maintenance_schedule1 field changed
      • changedInput schema / properties / changed_at / description
        Previous value: -"Optional โ€” when the user made this change (ISO 8601, UTC). An app sending a queued edit passes it, so an older edit never overwrites a newer one; it is then answered with applied: false"New value: +"Optional: when the user made this change (ISO 8601, UTC). An app sending a queued edit passes it, so an older edit never overwrites a newer one; it is then answered with applied: false"
    • Changedsuggest_next_step2 fields changed
      • addedOutput schema / properties / warning_codes
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "next_step",
        -  "category",
        -  "warnings"
        -]New value: +[
        +  "next_step",
        +  "category",
        +  "warnings",
        +  "warning_codes"
        +]
    • Changedupdate_bag6 fields changed
      • changedInput schema / properties / fields / properties / best_by_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / buy_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / frozen_at / description
        Previous value: -"Calendar day the bag went into the freezer, YYYY-MM-DD โ€” a day, not a timestamp"New value: +"Calendar day the bag went into the freezer, YYYY-MM-DD: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / opened_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / roast_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / unfrozen_at / description
        Previous value: -"Calendar day the bag came out, YYYY-MM-DD โ€” a day, not a timestamp"New value: +"Calendar day the bag came out, YYYY-MM-DD: a day, not a timestamp"
    • Changedupdate_bean8 fields changed
      • changedInput schema / properties / fields / properties / best_by_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / buy_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / frozen_at / description
        Previous value: -"Calendar day the bag went into the freezer, YYYY-MM-DD โ€” a day, not a timestamp"New value: +"Calendar day the bag went into the freezer, YYYY-MM-DD: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / notes / description
        Previous value: -"The coffee's own description โ€” roaster tasting notes, the dialing approach. Replaces the stored value; the optional reason is appended instead."New value: +"The coffee's own description: roaster tasting notes, the dialing approach. Replaces the stored value; the optional reason is appended instead."
      • changedInput schema / properties / fields / properties / opened_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / roast_date / description
        Previous value: -"Calendar day in YYYY-MM-DD format โ€” a day, not a timestamp"New value: +"Calendar day in YYYY-MM-DD format: a day, not a timestamp"
      • changedInput schema / properties / fields / properties / unfrozen_at / description
        Previous value: -"Calendar day the bag came out, YYYY-MM-DD โ€” a day, not a timestamp"New value: +"Calendar day the bag came out, YYYY-MM-DD: a day, not a timestamp"
      • changedInput schema / properties / reason / description
        Previous value: -"Optional free-text note, appended as an ordinary line to the coffee's notes โ€” or to the current bag's bag_notes when the call changed only bag fields. Omit it and nothing is written."New value: +"Optional free-text note, appended as an ordinary line to the coffee's notes, or to the current bag's bag_notes when the call changed only bag fields. Omit it and nothing is written."
    • Changedupdate_grinder2 fields changed
      • changedInput schema / properties / fields / properties / components_spec / description
        Previous value: -"JSON array of {name, per_step}, coarsest first โ€” the ring arithmetic of a compound collar, or the ordered settings of a named one"New value: +"JSON array of {name, per_step}, coarsest first: the ring arithmetic of a compound collar, or the ordered settings of a named one"
      • changedInput schema / properties / fields / properties / nominal_step / description
        Previous value: -"Smallest adjustment increment. On a numeric_stepless collar it is the precision labels are recorded in (0.1 records tenths) and the size of one click. numeric_stepped and clicks_single collars record whole steps whatever it says โ€” to record tenths, set setting_scheme numeric_stepless as well"New value: +"Smallest adjustment increment. On a numeric_stepless collar it is the precision labels are recorded in (0.1 records tenths) and the size of one click. numeric_stepped and clicks_single collars record whole steps whatever it says. To record tenths, set setting_scheme numeric_stepless as well"
  2. 5 tool updates
    • Changedget_dial_state6 fields changed
      • addedOutput schema / properties / active_machine / properties / settings / items / properties / provenance
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "default_quote": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "default_source": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "quote": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "source": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    }
        +  },
        +  "required": [
        +    "source",
        +    "quote",
        +    "default_source",
        +    "default_quote"
        +  ],
        +  "type": [
        +    "object",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / active_machine / properties / settings / items / required
        Previous value: -[
        -  "key",
        -  "label",
        -  "type",
        -  "options",
        -  "min",
        -  "max",
        -  "step",
        -  "unit",
        -  "default",
        -  "value"
        -]New value: +[
        +  "key",
        +  "label",
        +  "type",
        +  "options",
        +  "min",
        +  "max",
        +  "step",
        +  "unit",
        +  "default",
        +  "value",
        +  "provenance"
        +]
      • addedOutput schema / properties / locked_recipe / properties / machine_settings
        Added value: +{
        +  "additionalProperties": true,
        +  "type": [
        +    "object",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / locked_recipe / required
        Previous value: -[
        -  "id",
        -  "bean_id",
        -  "grinder_id",
        -  "machine_id",
        -  "program_id",
        -  "status",
        -  "grind_label",
        -  "grind_position_value",
        -  "dose_g",
        -  "target_yield_g",
        -  "target_time_s",
        -  "finish_action",
        -  "drink_intent",
        -  "profile",
        -  "kb_version",
        -  "locked_at",
        -  "grind_reading"
        -]New value: +[
        +  "id",
        +  "bean_id",
        +  "grinder_id",
        +  "machine_id",
        +  "program_id",
        +  "status",
        +  "grind_label",
        +  "grind_position_value",
        +  "dose_g",
        +  "target_yield_g",
        +  "target_time_s",
        +  "finish_action",
        +  "drink_intent",
        +  "profile",
        +  "kb_version",
        +  "locked_at",
        +  "machine_settings",
        +  "grind_reading"
        +]
      • addedOutput schema / properties / recent_shots / items / properties / machine_settings / additionalProperties
        Added value: +true
      • addedOutput schema / properties / recent_shots / items / properties / machine_settings / type
        Added value: +[
        +  "object",
        +  "null"
        +]
    • Changedlist_machines2 fields changed
      • addedOutput schema / properties / machines / items / properties / settings / items / properties / provenance
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "default_quote": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "default_source": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "quote": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "source": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    }
        +  },
        +  "required": [
        +    "source",
        +    "quote",
        +    "default_source",
        +    "default_quote"
        +  ],
        +  "type": [
        +    "object",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / machines / items / properties / settings / items / required
        Previous value: -[
        -  "key",
        -  "label",
        -  "type",
        -  "options",
        -  "min",
        -  "max",
        -  "step",
        -  "unit",
        -  "default",
        -  "value"
        -]New value: +[
        +  "key",
        +  "label",
        +  "type",
        +  "options",
        +  "min",
        +  "max",
        +  "step",
        +  "unit",
        +  "default",
        +  "value",
        +  "provenance"
        +]
    • Changedlist_recipes2 fields changed
      • addedOutput schema / properties / recipes / items / properties / machine_settings
        Added value: +{
        +  "additionalProperties": true,
        +  "type": [
        +    "object",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / recipes / items / required
        Previous value: -[
        -  "id",
        -  "bean_id",
        -  "grinder_id",
        -  "machine_id",
        -  "program_id",
        -  "status",
        -  "grind_label",
        -  "grind_position_value",
        -  "dose_g",
        -  "target_yield_g",
        -  "target_time_s",
        -  "finish_action",
        -  "drink_intent",
        -  "profile",
        -  "locked_at",
        -  "bean_name",
        -  "roaster_name",
        -  "grinder_name",
        -  "machine_name",
        -  "grind_reading"
        -]New value: +[
        +  "id",
        +  "bean_id",
        +  "grinder_id",
        +  "machine_id",
        +  "program_id",
        +  "status",
        +  "grind_label",
        +  "grind_position_value",
        +  "dose_g",
        +  "target_yield_g",
        +  "target_time_s",
        +  "finish_action",
        +  "drink_intent",
        +  "profile",
        +  "locked_at",
        +  "machine_settings",
        +  "bean_name",
        +  "roaster_name",
        +  "grinder_name",
        +  "machine_name",
        +  "grind_reading"
        +]
    • Changedlist_shots2 fields changed
      • addedOutput schema / properties / shots / items / properties / machine_settings / additionalProperties
        Added value: +true
      • changedOutput schema / properties / shots / items / properties / machine_settings / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "object",
        +  "null"
        +]
    • Changedset_active1 field changed
      • changedInput schema / properties / program_id / description
        Previous value: -"A program number from the active machine's list. null = leave unchanged"New value: +"A program number from the active machine's list; switching machines clears it. null = leave unchanged"
  3. 7 tool updates
    • Changedget_dial_state4 fields changed
      • addedOutput schema / properties / active_machine / properties / settings
        Added value: +{
        +  "items": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "default": {
        +        "type": [
        +          "number",
        +          "null",
        +          "string"
        +        ]
        +      },
        +      "key": {
        +        "type": "string"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "max": {
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "min": {
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "options": {
        +        "items": {
        +          "additionalProperties": true,
        +          "properties": {
        +            "label": {
        +              "type": "string"
        +            },
        +            "meaning": {
        +              "type": [
        +                "string",
        +                "null"
        +              ]
        +            },
        +            "value": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "value",
        +            "label",
        +            "meaning"
        +          ],
        +          "type": "object"
        +        },
        +        "type": [
        +          "null",
        +          "array"
        +        ]
        +      },
        +      "step": {},
        +      "type": {
        +        "type": "string"
        +      },
        +      "unit": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "value": {
        +        "type": [
        +          "number",
        +          "null",
        +          "string"
        +        ]
        +      }
        +    },
        +    "required": [
        +      "key",
        +      "label",
        +      "type",
        +      "options",
        +      "min",
        +      "max",
        +      "step",
        +      "unit",
        +      "default",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  "type": [
        +    "array",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / active_machine / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "control_type",
        -  "basket_size_grams",
        -  "boiler_type",
        -  "notes",
        -  "is_active",
        -  "prep_type",
        -  "prep_style",
        -  "archived",
        -  "photo",
        -  "tools",
        -  "connected_device",
        -  "built_in_grinder_id",
        -  "catalog_id",
        -  "hardness_dh"
        -]New value: +[
        +  "id",
        +  "name",
        +  "control_type",
        +  "basket_size_grams",
        +  "boiler_type",
        +  "notes",
        +  "is_active",
        +  "prep_type",
        +  "prep_style",
        +  "archived",
        +  "photo",
        +  "tools",
        +  "connected_device",
        +  "built_in_grinder_id",
        +  "catalog_id",
        +  "hardness_dh",
        +  "settings"
        +]
      • addedOutput schema / properties / recent_shots / items / properties / machine_settings
        Added value: +{}
      • changedOutput schema / properties / recent_shots / items / required
        Previous value: -[
        -  "id",
        -  "pulled_at",
        -  "bean_id",
        -  "grinder_id",
        -  "machine_id",
        -  "program_id",
        -  "grind_label",
        -  "grind_components",
        -  "grind_position_value",
        -  "dose_g",
        -  "yield_g",
        -  "time_s",
        -  "flow_rate_gps",
        -  "finish_action",
        -  "drink_intent",
        -  "flavor_notes",
        -  "sensory_tags",
        -  "observations",
        -  "temp_taste",
        -  "rating",
        -  "verdict",
        -  "data_confidence",
        -  "temperature_c",
        -  "bloom_time_s",
        -  "first_drip_time_s",
        -  "beverage_g",
        -  "tds",
        -  "ey_pct",
        -  "water_id",
        -  "vessel_name",
        -  "vessel_weight_g",
        -  "favourite",
        -  "best_brew",
        -  "tasted",
        -  "bag_id",
        -  "taste_pending"
        -]New value: +[
        +  "id",
        +  "pulled_at",
        +  "bean_id",
        +  "grinder_id",
        +  "machine_id",
        +  "program_id",
        +  "grind_label",
        +  "grind_components",
        +  "grind_position_value",
        +  "dose_g",
        +  "yield_g",
        +  "time_s",
        +  "flow_rate_gps",
        +  "finish_action",
        +  "drink_intent",
        +  "flavor_notes",
        +  "sensory_tags",
        +  "observations",
        +  "temp_taste",
        +  "rating",
        +  "verdict",
        +  "data_confidence",
        +  "temperature_c",
        +  "bloom_time_s",
        +  "first_drip_time_s",
        +  "beverage_g",
        +  "tds",
        +  "ey_pct",
        +  "water_id",
        +  "vessel_name",
        +  "vessel_weight_g",
        +  "favourite",
        +  "best_brew",
        +  "tasted",
        +  "bag_id",
        +  "machine_settings",
        +  "taste_pending"
        +]
    • Changedget_maintenance_guides1 field changed
      • addedOutput schema / properties / guides / items / properties / steps / items / properties / repeat
        Added value: +{
        +  "type": "integer"
        +}
    • Changedlist_machines13 fields changed
      • changedOutput schema / properties / machines / items / properties / catalog_id / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / catalog / properties / brand / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / catalog / properties / id / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / catalog / properties / model / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / due / type
        Previous value: -[
        -  "null",
        -  "object"
        -]New value: +[
        +  "object",
        +  "null"
        +]
      • addedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / also_covers / items
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / also_covers / type
        Added value: +[
        +  "array",
        +  "null"
        +]
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / duration_minutes / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / machine_alert / type
        Previous value: -[
        -  "object",
        -  "null"
        -]New value: +[
        +  "null",
        +  "object"
        +]
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / status / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / machines / items / properties / notes / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • addedOutput schema / properties / machines / items / properties / settings
        Added value: +{
        +  "items": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "default": {
        +        "type": [
        +          "number",
        +          "null",
        +          "string"
        +        ]
        +      },
        +      "key": {
        +        "type": "string"
        +      },
        +      "label": {
        +        "type": "string"
        +      },
        +      "max": {
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "min": {
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "options": {
        +        "items": {
        +          "additionalProperties": true,
        +          "properties": {
        +            "label": {
        +              "type": "string"
        +            },
        +            "meaning": {
        +              "type": [
        +                "string",
        +                "null"
        +              ]
        +            },
        +            "value": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "value",
        +            "label",
        +            "meaning"
        +          ],
        +          "type": "object"
        +        },
        +        "type": [
        +          "null",
        +          "array"
        +        ]
        +      },
        +      "step": {},
        +      "type": {
        +        "type": "string"
        +      },
        +      "unit": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "value": {
        +        "type": [
        +          "number",
        +          "null",
        +          "string"
        +        ]
        +      }
        +    },
        +    "required": [
        +      "key",
        +      "label",
        +      "type",
        +      "options",
        +      "min",
        +      "max",
        +      "step",
        +      "unit",
        +      "default",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  "type": [
        +    "array",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / machines / items / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "control_type",
        -  "basket_size_grams",
        -  "boiler_type",
        -  "notes",
        -  "prep_type",
        -  "prep_style",
        -  "archived",
        -  "built_in_grinder_id",
        -  "catalog_id",
        -  "hardness_dh",
        -  "tools_list",
        -  "programs",
        -  "maintenance"
        -]New value: +[
        +  "id",
        +  "name",
        +  "control_type",
        +  "basket_size_grams",
        +  "boiler_type",
        +  "notes",
        +  "prep_type",
        +  "prep_style",
        +  "archived",
        +  "built_in_grinder_id",
        +  "catalog_id",
        +  "hardness_dh",
        +  "tools_list",
        +  "programs",
        +  "maintenance",
        +  "settings"
        +]
    • Changedlist_shots2 fields changed
      • addedOutput schema / properties / shots / items / properties / machine_settings
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / shots / items / required
        Previous value: -[
        -  "id",
        -  "pulled_at",
        -  "bean_id",
        -  "grinder_id",
        -  "machine_id",
        -  "program_id",
        -  "grind_label",
        -  "grind_components",
        -  "grind_position_value",
        -  "dose_g",
        -  "yield_g",
        -  "time_s",
        -  "flow_rate_gps",
        -  "finish_action",
        -  "drink_intent",
        -  "flavor_notes",
        -  "sensory_tags",
        -  "observations",
        -  "temp_taste",
        -  "rating",
        -  "verdict",
        -  "data_confidence",
        -  "temperature_c",
        -  "bloom_time_s",
        -  "first_drip_time_s",
        -  "beverage_g",
        -  "tds",
        -  "ey_pct",
        -  "water_id",
        -  "vessel_name",
        -  "vessel_weight_g",
        -  "favourite",
        -  "best_brew",
        -  "tasted",
        -  "bag_id",
        -  "bean_name",
        -  "taste_pending"
        -]New value: +[
        +  "id",
        +  "pulled_at",
        +  "bean_id",
        +  "grinder_id",
        +  "machine_id",
        +  "program_id",
        +  "grind_label",
        +  "grind_components",
        +  "grind_position_value",
        +  "dose_g",
        +  "yield_g",
        +  "time_s",
        +  "flow_rate_gps",
        +  "finish_action",
        +  "drink_intent",
        +  "flavor_notes",
        +  "sensory_tags",
        +  "observations",
        +  "temp_taste",
        +  "rating",
        +  "verdict",
        +  "data_confidence",
        +  "temperature_c",
        +  "bloom_time_s",
        +  "first_drip_time_s",
        +  "beverage_g",
        +  "tds",
        +  "ey_pct",
        +  "water_id",
        +  "vessel_name",
        +  "vessel_weight_g",
        +  "favourite",
        +  "best_brew",
        +  "tasted",
        +  "bag_id",
        +  "machine_settings",
        +  "bean_name",
        +  "taste_pending"
        +]
    • Changedlog_shot1 field changed
      • addedInput schema / properties / machine_settings
        Added value: +{
        +  "description": "Only when this one shot was pulled with a selector somewhere other than the machine's recorded settings: {key: position}. The shot is otherwise stamped with those automatically; a lasting change goes through update_machine.",
        +  "maxProperties": 16,
        +  "type": "object"
        +}
    • Changedupdate_machine1 field changed
      • addedInput schema / properties / fields / properties / settings
        Added value: +{
        +  "description": "Where the machine's selectors now stand, as {key: position} from list_machines settings, e.g. {\"brew_temperature\": \"ii\"}. Only the keys given change; a null position clears one, null clears all. Shots are stamped with these.",
        +  "type": [
        +    "object",
        +    "null"
        +  ]
        +}
    • Changedupdate_shot1 field changed
      • addedInput schema / properties / fields / properties / machine_settings
        Added value: +{
        +  "description": "The machine's selector positions for this shot, {key: position}; replaces what was stamped, null clears it",
        +  "maxProperties": 16,
        +  "type": [
        +    "object",
        +    "null"
        +  ]
        +}
  4. 1 tool update
    • Changedget_maintenance_guides2 fields changed
      • addedOutput schema / properties / guides / items / properties / steps / items / properties / anchor
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / properties / guides / items / properties / steps / items / required
        Previous value: -[
        -  "n",
        -  "text",
        -  "source"
        -]New value: +[
        +  "n",
        +  "text",
        +  "source",
        +  "anchor"
        +]
  5. 1 tool update
    • Changedlock_recipe2 fields changed
      • addedOutput schema / properties / recipe_id
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "status",
        -  "message"
        -]New value: +[
        +  "status",
        +  "recipe_id",
        +  "message"
        +]
  6. 11 tool updates
    • Changedcompute_age2 fields changed
      • removedOutput schema / properties / days_since_opened / type
        Removed value: -"null"
      • removedOutput schema / properties / grams_remaining / type
        Removed value: -"null"
    • Changedget_dial_state86 fields changed
      • removedOutput schema / properties / active_coffee / properties / acidity / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / arabica_pct / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / aromatics / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / attachments / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / bag_weight_g / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / best_by_date / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / buy_date / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / cost / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / currency / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / days_since_opened / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / ean / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / frozen_at / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / frozen_note / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / frozen_storage / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / grams_remaining / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / opened_date / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / qr_code / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / storage / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag / properties / unfrozen_at / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bag_weight_g / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / bean_mix / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / best_by_date / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / body / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / buy_date / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / co2e_kg / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / cost / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / cupping_points / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / currency / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / days_since_opened / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / decaffeinated / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / ean / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / favourite / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / frozen_at / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / frozen_note / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / frozen_storage / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / grams_remaining / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / notes / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / opened_date / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / origin / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / qr_code / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / rating / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / rest_window_days_max / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / rest_window_days_min / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / roast_custom / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / roast_range / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / roasting_type / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / storage / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / sweetness / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / unfrozen_at / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / url / type
        Removed value: -"null"
      • removedOutput schema / properties / active_coffee / properties / variety / type
        Removed value: -"null"
      • removedOutput schema / properties / active_grinder / properties / built_in_machine_id / type
        Removed value: -"null"
      • removedOutput schema / properties / active_grinder / properties / catalog_id / type
        Removed value: -"null"
      • removedOutput schema / properties / active_grinder / properties / max_value / type
        Removed value: -"null"
      • removedOutput schema / properties / active_grinder / properties / min_value / type
        Removed value: -"null"
      • removedOutput schema / properties / active_grinder / properties / notes / type
        Removed value: -"null"
      • removedOutput schema / properties / active_grinder / properties / photo / type
        Removed value: -"null"
      • removedOutput schema / properties / active_machine / properties / built_in_grinder_id / type
        Removed value: -"null"
      • removedOutput schema / properties / active_machine / properties / connected_device / type
        Removed value: -"null"
      • removedOutput schema / properties / active_machine / properties / hardness_dh / type
        Removed value: -"null"
      • removedOutput schema / properties / active_machine / properties / notes / type
        Removed value: -"null"
      • removedOutput schema / properties / active_machine / properties / photo / type
        Removed value: -"null"
      • removedOutput schema / properties / active_machine / properties / prep_style / type
        Removed value: -"null"
      • removedOutput schema / properties / active_machine / properties / prep_type / type
        Removed value: -"null"
      • removedOutput schema / properties / active_machine / properties / tools / type
        Removed value: -"null"
      • removedOutput schema / properties / active_program / type
        Removed value: -"null"
      • removedOutput schema / properties / locked_recipe / properties / grind_reading / type
        Removed value: -"null"
      • removedOutput schema / properties / locked_recipe / properties / program_id / type
        Removed value: -"null"
      • removedOutput schema / properties / maintenance_summary / properties / most_urgent / properties / due_at / type
        Removed value: -"null"
      • removedOutput schema / properties / maintenance_summary / properties / most_urgent / properties / last_at / type
        Removed value: -"null"
      • removedOutput schema / properties / maintenance_summary / properties / most_urgent / properties / muted_until / type
        Removed value: -"null"
      • removedOutput schema / properties / maintenance_summary / properties / most_urgent / properties / overdue_at / type
        Removed value: -"null"
      • removedOutput schema / properties / maintenance_summary / properties / most_urgent / properties / soon_at / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_recommendations / items / properties / based_on_shot / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / beverage_g / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / bloom_time_s / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / ey_pct / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / first_drip_time_s / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / program_id / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / rating / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / tds / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / temperature_c / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / verdict / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / vessel_name / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / vessel_weight_g / type
        Removed value: -"null"
      • removedOutput schema / properties / recent_shots / items / properties / water_id / type
        Removed value: -"null"
    • Changedget_maintenance_guides3 fields changed
      • removedOutput schema / properties / guides / items / properties / machine_alert / properties / can_disable / type
        Removed value: -"null"
      • removedOutput schema / properties / guides / items / properties / machine_alert / properties / depends_on_setting / type
        Removed value: -"null"
      • removedOutput schema / properties / guides / items / properties / machine_alert / properties / threshold / type
        Removed value: -"null"
    • Changedlist_beans41 fields changed
      • removedOutput schema / properties / beans / items / properties / acidity / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / arabica_pct / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / aromatics / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / best_by_date / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / buy_date / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / days_since_opened / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / ean / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / frozen_at / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / frozen_note / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / frozen_storage / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / opened_date / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / qr_code / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / storage / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / bags / items / properties / unfrozen_at / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / best_by_date / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / body / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / buy_date / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / cost / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / cupping_points / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / currency / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / days_since_opened / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / ean / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / frozen_at / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / frozen_note / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / frozen_storage / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / opened_date / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / origin / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / origins / items / properties / elevation_m / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / origins / items / properties / elevation_max_m / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / origins / items / properties / farm / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / origins / items / properties / farmer / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / origins / items / properties / harvest / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / origins / items / properties / processing / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / qr_code / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / rating / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / roasting_type / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / storage / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / sweetness / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / unfrozen_at / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / url / type
        Removed value: -"null"
      • removedOutput schema / properties / beans / items / properties / variety / type
        Removed value: -"null"
    • Changedlist_grinders11 fields changed
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / muted_until / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / guide_id / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / hardness / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / sensitivity / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / guide / properties / also_covers / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / guide / properties / duration_minutes / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / guide / properties / duration_note / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / guide / properties / machine_alert / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / guide / properties / market / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / schedule / properties / every / type
        Removed value: -"null"
      • removedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / schedule / properties / muted_until / type
        Removed value: -"null"
    • Changedlist_machines29 fields changed
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / disturbs_note / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / epoch_at / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / epoch_id / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / epoch_task / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / evidence / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / offset_at / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / offset_source / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / offset_unit / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / offset_value / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / calibration / properties / reference_recipe_id / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / catalog / properties / match / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / catalog / properties / via / type
        Removed value: -"null"
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / due / properties
        Previous value: -[]New value: +{}
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / entries / items / properties / evidence / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / entries / items / properties / note / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / entries / items / properties / offset_at / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / entries / items / properties / offset_source / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / entries / items / properties / offset_value / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / sensitivity / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / disturbs_prompt / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / also_covers / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / duration_note / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / machine_alert / properties / can_disable / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / machine_alert / properties / depends_on_setting / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / machine_alert / properties / threshold / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / market / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / guide / properties / variant / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / maintenance / properties / tasks / items / properties / opened_by / type
        Removed value: -"null"
      • removedOutput schema / properties / machines / items / properties / programs / items / properties / target_time_s / type
        Removed value: -"null"
    • Changedlist_recipes3 fields changed
      • removedOutput schema / properties / recipes / items / properties / grind_reading / properties / label / type
        Removed value: -"null"
      • removedOutput schema / properties / recipes / items / properties / grind_reading / properties / offset_clicks / type
        Removed value: -"null"
      • removedOutput schema / properties / recipes / items / properties / grind_reading / properties / offset_direction / type
        Removed value: -"null"
    • Changedlist_scales11 fields changed
      • removedOutput schema / properties / scales / items / properties / auto_tare / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / auto_timer / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / capacity_g / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / connectivity / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / depth_mm / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / flow_rate_display / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / height_mm / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / notes / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / power / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / water_resistance / type
        Removed value: -"null"
      • removedOutput schema / properties / scales / items / properties / width_mm / type
        Removed value: -"null"
    • Changedlist_shots12 fields changed
      • removedOutput schema / properties / shots / items / properties / beverage_g / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / bloom_time_s / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / ey_pct / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / first_drip_time_s / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / program_id / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / rating / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / tds / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / temperature_c / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / verdict / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / vessel_name / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / vessel_weight_g / type
        Removed value: -"null"
      • removedOutput schema / properties / shots / items / properties / water_id / type
        Removed value: -"null"
    • Changedlist_waters6 fields changed
      • removedOutput schema / properties / waters / items / properties / calcium / type
        Removed value: -"null"
      • removedOutput schema / properties / waters / items / properties / magnesium / type
        Removed value: -"null"
      • removedOutput schema / properties / waters / items / properties / notes / type
        Removed value: -"null"
      • removedOutput schema / properties / waters / items / properties / sodium / type
        Removed value: -"null"
      • removedOutput schema / properties / waters / items / properties / tds / type
        Removed value: -"null"
      • removedOutput schema / properties / waters / items / properties / type / type
        Removed value: -"null"
    • Changedset_maintenance_offset2 fields changed
      • removedOutput schema / properties / entry / properties / details / properties / to / properties / components_spec / type
        Removed value: -"null"
      • removedOutput schema / properties / entry / properties / guide_id / type
        Removed value: -"null"
  7. 5 tool updates
    • Changedget_dial_state5 fields changed
      • addedOutput schema / properties / maintenance_summary / properties / most_urgent / properties / soon
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / maintenance_summary / properties / most_urgent / properties / soon_at
        Added value: +{
        +  "type": "null"
        +}
      • changedOutput schema / properties / maintenance_summary / properties / most_urgent / required
        Previous value: -[
        -  "equipment_kind",
        -  "equipment_id",
        -  "equipment_name",
        -  "task",
        -  "label",
        -  "class",
        -  "state",
        -  "ratio",
        -  "basis",
        -  "every",
        -  "done",
        -  "remaining",
        -  "last_at",
        -  "every_source",
        -  "lower_bound",
        -  "due_at",
        -  "overdue_at",
        -  "muted",
        -  "muted_until"
        -]New value: +[
        +  "equipment_kind",
        +  "equipment_id",
        +  "equipment_name",
        +  "task",
        +  "label",
        +  "class",
        +  "state",
        +  "ratio",
        +  "basis",
        +  "every",
        +  "done",
        +  "remaining",
        +  "last_at",
        +  "every_source",
        +  "lower_bound",
        +  "soon",
        +  "soon_at",
        +  "due_at",
        +  "overdue_at",
        +  "muted",
        +  "muted_until"
        +]
      • addedOutput schema / properties / maintenance_summary / properties / soon_count
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / properties / maintenance_summary / required
        Previous value: -[
        -  "computed_at",
        -  "catalog_version",
        -  "most_urgent",
        -  "due_count",
        -  "overdue_count",
        -  "calibration_state"
        -]New value: +[
        +  "computed_at",
        +  "catalog_version",
        +  "most_urgent",
        +  "due_count",
        +  "overdue_count",
        +  "soon_count",
        +  "calibration_state"
        +]
    • Changedlist_grinders3 fields changed
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / soon
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / soon_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / required
        Previous value: -[
        -  "state",
        -  "ratio",
        -  "basis",
        -  "every",
        -  "done",
        -  "remaining",
        -  "lower_bound",
        -  "due_at",
        -  "overdue_at",
        -  "last_at",
        -  "every_source",
        -  "muted",
        -  "muted_until"
        -]New value: +[
        +  "state",
        +  "ratio",
        +  "basis",
        +  "every",
        +  "done",
        +  "remaining",
        +  "lower_bound",
        +  "soon",
        +  "soon_at",
        +  "due_at",
        +  "overdue_at",
        +  "last_at",
        +  "every_source",
        +  "muted",
        +  "muted_until"
        +]
    • Changedlist_machines3 fields changed
      • addedOutput schema / properties / machines / items / properties / maintenance / properties / due / additionalProperties / properties / soon
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / machines / items / properties / maintenance / properties / due / additionalProperties / properties / soon_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / machines / items / properties / maintenance / properties / due / additionalProperties / required
        Previous value: -[
        -  "state",
        -  "ratio",
        -  "basis",
        -  "every",
        -  "done",
        -  "remaining",
        -  "lower_bound",
        -  "due_at",
        -  "overdue_at",
        -  "last_at",
        -  "every_source",
        -  "muted",
        -  "muted_until"
        -]New value: +[
        +  "state",
        +  "ratio",
        +  "basis",
        +  "every",
        +  "done",
        +  "remaining",
        +  "lower_bound",
        +  "soon",
        +  "soon_at",
        +  "due_at",
        +  "overdue_at",
        +  "last_at",
        +  "every_source",
        +  "muted",
        +  "muted_until"
        +]
    • Changedlist_maintenance_due3 fields changed
      • addedOutput schema / properties / items / items / properties / soon
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / items / items / properties / soon_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / items / items / required
        Previous value: -[
        -  "equipment_kind",
        -  "equipment_id",
        -  "equipment_name",
        -  "task",
        -  "label",
        -  "class",
        -  "state",
        -  "ratio",
        -  "basis",
        -  "every",
        -  "done",
        -  "remaining",
        -  "last_at",
        -  "every_source",
        -  "lower_bound",
        -  "due_at",
        -  "overdue_at",
        -  "muted",
        -  "muted_until"
        -]New value: +[
        +  "equipment_kind",
        +  "equipment_id",
        +  "equipment_name",
        +  "task",
        +  "label",
        +  "class",
        +  "state",
        +  "ratio",
        +  "basis",
        +  "every",
        +  "done",
        +  "remaining",
        +  "last_at",
        +  "every_source",
        +  "lower_bound",
        +  "soon",
        +  "soon_at",
        +  "due_at",
        +  "overdue_at",
        +  "muted",
        +  "muted_until"
        +]
    • Changedset_maintenance_schedule2 fields changed
      • addedOutput schema / properties / due / properties / soon
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / due / properties / soon_at
        Added value: +{
        +  "type": "string"
        +}
  8. 3 tool updates
    • Changedregister_coffee2 fields changed
      • addedOutput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "status",
        -  "bean_id",
        -  "bag_id",
        -  "message"
        -]New value: +[
        +  "status",
        +  "bean_id",
        +  "bag_id",
        +  "active",
        +  "message"
        +]
    • Changedregister_grinder2 fields changed
      • addedOutput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "status",
        -  "grinder_id",
        -  "message"
        -]New value: +[
        +  "status",
        +  "grinder_id",
        +  "active",
        +  "message"
        +]
    • Changedregister_machine2 fields changed
      • addedOutput schema / properties / active
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "status",
        -  "machine_id",
        -  "message"
        -]New value: +[
        +  "status",
        +  "machine_id",
        +  "active",
        +  "message"
        +]
  9. 12 tool updates
    • Changedget_dial_state7 fields changed
      • addedOutput schema / properties / active_grinder / properties / catalog_id
        Added value: +{
        +  "type": "null"
        +}
      • changedOutput schema / properties / active_grinder / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "motor_type",
        -  "burr_type",
        -  "setting_scheme",
        -  "direction_convention",
        -  "nominal_step",
        -  "components_spec",
        -  "min_value",
        -  "max_value",
        -  "microns_per_step",
        -  "notes",
        -  "is_active",
        -  "archived",
        -  "photo",
        -  "setting_label",
        -  "setting_components",
        -  "position_value",
        -  "source",
        -  "verified_at",
        -  "built_in_machine_id"
        -]New value: +[
        +  "id",
        +  "name",
        +  "motor_type",
        +  "burr_type",
        +  "setting_scheme",
        +  "direction_convention",
        +  "nominal_step",
        +  "components_spec",
        +  "min_value",
        +  "max_value",
        +  "microns_per_step",
        +  "notes",
        +  "is_active",
        +  "archived",
        +  "photo",
        +  "catalog_id",
        +  "setting_label",
        +  "setting_components",
        +  "position_value",
        +  "source",
        +  "verified_at",
        +  "built_in_machine_id"
        +]
      • addedOutput schema / properties / active_machine / properties / catalog_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / active_machine / properties / hardness_dh
        Added value: +{
        +  "type": "null"
        +}
      • changedOutput schema / properties / active_machine / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "control_type",
        -  "basket_size_grams",
        -  "boiler_type",
        -  "notes",
        -  "is_active",
        -  "prep_type",
        -  "prep_style",
        -  "archived",
        -  "photo",
        -  "tools",
        -  "connected_device",
        -  "built_in_grinder_id"
        -]New value: +[
        +  "id",
        +  "name",
        +  "control_type",
        +  "basket_size_grams",
        +  "boiler_type",
        +  "notes",
        +  "is_active",
        +  "prep_type",
        +  "prep_style",
        +  "archived",
        +  "photo",
        +  "tools",
        +  "connected_device",
        +  "built_in_grinder_id",
        +  "catalog_id",
        +  "hardness_dh"
        +]
      • addedOutput schema / properties / maintenance_summary
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "calibration_state": {
        +      "type": "string"
        +    },
        +    "catalog_version": {
        +      "type": "string"
        +    },
        +    "computed_at": {
        +      "type": "string"
        +    },
        +    "due_count": {
        +      "type": "integer"
        +    },
        +    "most_urgent": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "basis": {
        +          "type": "string"
        +        },
        +        "class": {
        +          "type": "string"
        +        },
        +        "done": {
        +          "type": "integer"
        +        },
        +        "due_at": {
        +          "type": "null"
        +        },
        +        "equipment_id": {
        +          "type": "integer"
        +        },
        +        "equipment_kind": {
        +          "type": "string"
        +        },
        +        "equipment_name": {
        +          "type": "string"
        +        },
        +        "every": {
        +          "type": "integer"
        +        },
        +        "every_source": {
        +          "type": "string"
        +        },
        +        "label": {
        +          "type": "string"
        +        },
        +        "last_at": {
        +          "type": "null"
        +        },
        +        "lower_bound": {
        +          "type": "boolean"
        +        },
        +        "muted": {
        +          "type": "boolean"
        +        },
        +        "muted_until": {
        +          "type": "null"
        +        },
        +        "overdue_at": {
        +          "type": "null"
        +        },
        +        "ratio": {
        +          "type": "number"
        +        },
        +        "remaining": {
        +          "type": "integer"
        +        },
        +        "state": {
        +          "type": "string"
        +        },
        +        "task": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "equipment_kind",
        +        "equipment_id",
        +        "equipment_name",
        +        "task",
        +        "label",
        +        "class",
        +        "state",
        +        "ratio",
        +        "basis",
        +        "every",
        +        "done",
        +        "remaining",
        +        "last_at",
        +        "every_source",
        +        "lower_bound",
        +        "due_at",
        +        "overdue_at",
        +        "muted",
        +        "muted_until"
        +      ],
        +      "type": "object"
        +    },
        +    "overdue_count": {
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "computed_at",
        +    "catalog_version",
        +    "most_urgent",
        +    "due_count",
        +    "overdue_count",
        +    "calibration_state"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "active_coffee",
        -  "active_grinder",
        -  "active_machine",
        -  "active_program",
        -  "recent_shots",
        -  "recent_recommendations",
        -  "locked_recipe"
        -]New value: +[
        +  "active_coffee",
        +  "active_grinder",
        +  "active_machine",
        +  "active_program",
        +  "recent_shots",
        +  "recent_recommendations",
        +  "locked_recipe",
        +  "maintenance_summary"
        +]
    • Addedget_maintenance_guides
    • Changedlist_grinders45 fields changed
      • addedInput schema / properties / maintenance
        Added value: +{
        +  "description": "How much of each row's maintenance block to include. compact (default): every task with its class, due state, schedule and guide. full: also the maker's own words โ€” quote, source, alternates, the interval as written.",
        +  "enum": [
        +    "compact",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • changedOutput schema / properties / grinders / items / properties / built_in_machine_id / type
        Previous value: -"null"New value: +[
        +  "integer",
        +  "null"
        +]
      • addedOutput schema / properties / grinders / items / properties / catalog_id
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / disturbs_note / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / epoch_at / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / epoch_id / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / epoch_task / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / offset_at / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / offset_source / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / offset_value / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / catalog
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "brand": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "declined": {
        +      "type": "boolean"
        +    },
        +    "id": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "match": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "brand": {
        +          "type": "string"
        +        },
        +        "by": {
        +          "type": "string"
        +        },
        +        "id": {
        +          "type": "string"
        +        },
        +        "model": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [],
        +      "type": [
        +        "null",
        +        "object"
        +      ]
        +    },
        +    "model": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "via": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "brand",
        +    "model",
        +    "via",
        +    "match",
        +    "declined"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / catalog_version
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / computed_at
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / basis / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / done / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / due_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / every / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / every_source
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / lower_bound
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / muted
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / muted_until
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / overdue_at
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / ratio / type
        Previous value: -[
        -  "number",
        -  "integer"
        -]New value: +[
        +  "integer",
        +  "number"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / remaining / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / required
        Previous value: -[
        -  "state",
        -  "ratio",
        -  "basis",
        -  "every",
        -  "done",
        -  "remaining",
        -  "last_at"
        -]New value: +[
        +  "state",
        +  "ratio",
        +  "basis",
        +  "every",
        +  "done",
        +  "remaining",
        +  "lower_bound",
        +  "due_at",
        +  "overdue_at",
        +  "last_at",
        +  "every_source",
        +  "muted",
        +  "muted_until"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / guide_id
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / task_label
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / required
        Previous value: -[
        -  "id",
        -  "equipment_kind",
        -  "equipment_id",
        -  "task",
        -  "performed_at",
        -  "disturbs_zero",
        -  "note",
        -  "offset_value",
        -  "offset_source",
        -  "offset_at",
        -  "evidence",
        -  "details",
        -  "details_version",
        -  "created_at",
        -  "details_known"
        -]New value: +[
        +  "id",
        +  "equipment_kind",
        +  "equipment_id",
        +  "task",
        +  "performed_at",
        +  "disturbs_zero",
        +  "note",
        +  "offset_value",
        +  "offset_source",
        +  "offset_at",
        +  "evidence",
        +  "details",
        +  "details_version",
        +  "created_at",
        +  "guide_id",
        +  "details_known",
        +  "task_label"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / entries_total
        Added value: +{
        +  "type": "integer"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / hardness
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / class
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / details_fields / items
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "hint": {
        +      "type": "string"
        +    },
        +    "key": {
        +      "type": "string"
        +    },
        +    "label": {
        +      "type": "string"
        +    },
        +    "required": {
        +      "type": "boolean"
        +    },
        +    "type": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "key",
        +    "type",
        +    "label",
        +    "hint",
        +    "required"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / disturbs_prompt
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / every / type
        Previous value: -[
        -  "object",
        -  "null"
        -]New value: +[
        +  "null",
        +  "object"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / every_source
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "days": {
        +      "type": "string"
        +    },
        +    "grams": {
        +      "type": "string"
        +    },
        +    "shots": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / guide
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "also_covers": {
        +      "type": "null"
        +    },
        +    "basis": {
        +      "type": "string"
        +    },
        +    "duration_minutes": {
        +      "type": "null"
        +    },
        +    "duration_note": {
        +      "type": "null"
        +    },
        +    "id": {
        +      "type": "string"
        +    },
        +    "machine_alert": {
        +      "type": "null"
        +    },
        +    "market": {
        +      "type": "null"
        +    },
        +    "scope": {
        +      "type": "string"
        +    },
        +    "steps": {
        +      "type": "integer"
        +    },
        +    "title": {
        +      "type": "string"
        +    },
        +    "variant": {
        +      "type": "string"
        +    },
        +    "warnings": {
        +      "type": "integer"
        +    }
        +  },
        +  "required": [],
        +  "type": [
        +    "object",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / schedule
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "enabled": {
        +      "type": "boolean"
        +    },
        +    "every": {
        +      "type": "null"
        +    },
        +    "muted_until": {
        +      "type": "null"
        +    }
        +  },
        +  "required": [],
        +  "type": [
        +    "null",
        +    "object"
        +  ]
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / status
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / trigger
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / required
        Previous value: -[
        -  "value",
        -  "kind",
        -  "label",
        -  "sub",
        -  "disturbs_zero",
        -  "every",
        -  "why",
        -  "disturbs_note",
        -  "offset_unit",
        -  "offset_integral",
        -  "scheduled",
        -  "opened_by",
        -  "details_version",
        -  "details_fields"
        -]New value: +[
        +  "value",
        +  "kind",
        +  "label",
        +  "sub",
        +  "disturbs_zero",
        +  "every",
        +  "why",
        +  "disturbs_note",
        +  "offset_unit",
        +  "offset_integral",
        +  "scheduled",
        +  "opened_by",
        +  "details_version",
        +  "details_fields",
        +  "class",
        +  "status",
        +  "trigger",
        +  "every_source",
        +  "disturbs_prompt",
        +  "guide",
        +  "schedule"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / required
        Previous value: -[
        -  "tasks",
        -  "due",
        -  "calibration",
        -  "sensitivity",
        -  "entries"
        -]New value: +[
        +  "tasks",
        +  "due",
        +  "calibration",
        +  "sensitivity",
        +  "entries",
        +  "entries_total",
        +  "catalog_version",
        +  "computed_at",
        +  "catalog",
        +  "hardness"
        +]
      • changedOutput schema / properties / grinders / items / properties / microns_per_step / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • changedOutput schema / properties / grinders / items / properties / nominal_step / type
        Previous value: -[
        -  "number",
        -  "integer"
        -]New value: +[
        +  "integer",
        +  "number"
        +]
      • changedOutput schema / properties / grinders / items / properties / notes / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "motor_type",
        -  "burr_type",
        -  "setting_scheme",
        -  "direction_convention",
        -  "nominal_step",
        -  "components_spec",
        -  "min_value",
        -  "max_value",
        -  "microns_per_step",
        -  "notes",
        -  "archived",
        -  "setting_label",
        -  "setting_components",
        -  "position_value",
        -  "source",
        -  "verified_at",
        -  "built_in_machine_id",
        -  "maintenance"
        -]New value: +[
        +  "id",
        +  "name",
        +  "motor_type",
        +  "burr_type",
        +  "setting_scheme",
        +  "direction_convention",
        +  "nominal_step",
        +  "components_spec",
        +  "min_value",
        +  "max_value",
        +  "microns_per_step",
        +  "notes",
        +  "archived",
        +  "catalog_id",
        +  "setting_label",
        +  "setting_components",
        +  "position_value",
        +  "source",
        +  "verified_at",
        +  "built_in_machine_id",
        +  "maintenance"
        +]
    • Changedlist_machines6 fields changed
      • addedInput schema / properties / maintenance
        Added value: +{
        +  "description": "How much of each row's maintenance block to include. compact (default): every task with its class, due state, schedule and guide. full: also the maker's own words โ€” quote, source, alternates, the interval as written.",
        +  "enum": [
        +    "compact",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • changedOutput schema / properties / machines / items / properties / built_in_grinder_id / type
        Previous value: -"null"New value: +[
        +  "null",
        +  "integer"
        +]
      • addedOutput schema / properties / machines / items / properties / catalog_id
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • addedOutput schema / properties / machines / items / properties / hardness_dh
        Added value: +{
        +  "type": [
        +    "null",
        +    "number"
        +  ]
        +}
      • addedOutput schema / properties / machines / items / properties / maintenance
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "calibration": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "disturbs_note": {
        +          "type": "null"
        +        },
        +        "epoch_at": {
        +          "type": "null"
        +        },
        +        "epoch_id": {
        +          "type": "null"
        +        },
        +        "epoch_task": {
        +          "type": "null"
        +        },
        +        "evidence": {
        +          "type": "null"
        +        },
        +        "offset_at": {
        +          "type": "null"
        +        },
        +        "offset_source": {
        +          "type": "null"
        +        },
        +        "offset_unit": {
        +          "type": "null"
        +        },
        +        "offset_value": {
        +          "type": "null"
        +        },
        +        "reference_recipe_id": {
        +          "type": "null"
        +        },
        +        "stale_recipe_count": {
        +          "type": "integer"
        +        },
        +        "state": {
        +          "type": "string"
        +        },
        +        "untranslatable_recipe_count": {
        +          "type": "integer"
        +        }
        +      },
        +      "required": [
        +        "stale_recipe_count",
        +        "untranslatable_recipe_count",
        +        "reference_recipe_id",
        +        "state",
        +        "epoch_id",
        +        "epoch_task",
        +        "disturbs_note",
        +        "epoch_at",
        +        "offset_value",
        +        "offset_unit",
        +        "offset_source",
        +        "offset_at",
        +        "evidence"
        +      ],
        +      "type": "object"
        +    },
        +    "catalog": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "brand": {
        +          "type": [
        +            "null",
        +            "string"
        +          ]
        +        },
        +        "declined": {
        +          "type": "boolean"
        +        },
        +        "id": {
        +          "type": [
        +            "null",
        +            "string"
        +          ]
        +        },
        +        "match": {
        +          "type": "null"
        +        },
        +        "model": {
        +          "type": [
        +            "null",
        +            "string"
        +          ]
        +        },
        +        "via": {
        +          "type": "null"
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "brand",
        +        "model",
        +        "via",
        +        "match",
        +        "declined"
        +      ],
        +      "type": "object"
        +    },
        +    "catalog_version": {
        +      "type": "string"
        +    },
        +    "computed_at": {
        +      "type": "string"
        +    },
        +    "due": {
        +      "additionalProperties": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "basis": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "done": {
        +            "type": [
        +              "null",
        +              "integer"
        +            ]
        +          },
        +          "due_at": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "every": {
        +            "type": [
        +              "null",
        +              "integer"
        +            ]
        +          },
        +          "every_source": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "last_at": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "lower_bound": {
        +            "type": "boolean"
        +          },
        +          "muted": {
        +            "type": "boolean"
        +          },
        +          "muted_until": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "overdue_at": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "ratio": {
        +            "type": [
        +              "integer",
        +              "number"
        +            ]
        +          },
        +          "remaining": {
        +            "type": [
        +              "null",
        +              "integer"
        +            ]
        +          },
        +          "state": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "state",
        +          "ratio",
        +          "basis",
        +          "every",
        +          "done",
        +          "remaining",
        +          "lower_bound",
        +          "due_at",
        +          "overdue_at",
        +          "last_at",
        +          "every_source",
        +          "muted",
        +          "muted_until"
        +        ],
        +        "type": "object"
        +      },
        +      "properties": [],
        +      "required": [],
        +      "type": [
        +        "null",
        +        "object"
        +      ]
        +    },
        +    "entries": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "created_at": {
        +            "type": "string"
        +          },
        +          "details": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "filter_id": {
        +                "type": "string"
        +              },
        +              "label": {
        +                "type": "string"
        +              },
        +              "product": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [],
        +            "type": "object"
        +          },
        +          "details_known": {
        +            "type": "boolean"
        +          },
        +          "details_version": {
        +            "type": "integer"
        +          },
        +          "disturbs_zero": {
        +            "type": "integer"
        +          },
        +          "equipment_id": {
        +            "type": "integer"
        +          },
        +          "equipment_kind": {
        +            "type": "string"
        +          },
        +          "evidence": {
        +            "type": "null"
        +          },
        +          "guide_id": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "id": {
        +            "type": "integer"
        +          },
        +          "note": {
        +            "type": "null"
        +          },
        +          "offset_at": {
        +            "type": "null"
        +          },
        +          "offset_source": {
        +            "type": "null"
        +          },
        +          "offset_value": {
        +            "type": "null"
        +          },
        +          "performed_at": {
        +            "type": "string"
        +          },
        +          "task": {
        +            "type": "string"
        +          },
        +          "task_label": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "equipment_kind",
        +          "equipment_id",
        +          "task",
        +          "performed_at",
        +          "disturbs_zero",
        +          "note",
        +          "offset_value",
        +          "offset_source",
        +          "offset_at",
        +          "evidence",
        +          "details",
        +          "details_version",
        +          "created_at",
        +          "guide_id",
        +          "details_known",
        +          "task_label"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "entries_total": {
        +      "type": "integer"
        +    },
        +    "hardness": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "dh": {
        +          "type": [
        +            "null",
        +            "number"
        +          ]
        +        },
        +        "dkh": {
        +          "type": [
        +            "null",
        +            "number"
        +          ]
        +        },
        +        "dkh_source": {
        +          "type": [
        +            "null",
        +            "string"
        +          ]
        +        },
        +        "source": {
        +          "type": [
        +            "null",
        +            "string"
        +          ]
        +        }
        +      },
        +      "required": [
        +        "dh",
        +        "dkh",
        +        "source",
        +        "dkh_source"
        +      ],
        +      "type": "object"
        +    },
        +    "sensitivity": {
        +      "type": "null"
        +    },
        +    "tasks": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "class": {
        +            "type": "string"
        +          },
        +          "details_fields": {
        +            "items": {
        +              "additionalProperties": true,
        +              "properties": {
        +                "hint": {
        +                  "type": [
        +                    "string",
        +                    "null"
        +                  ]
        +                },
        +                "key": {
        +                  "type": "string"
        +                },
        +                "label": {
        +                  "type": "string"
        +                },
        +                "options": {
        +                  "items": {
        +                    "additionalProperties": true,
        +                    "properties": {
        +                      "id": {
        +                        "type": "string"
        +                      },
        +                      "label": {
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "id",
        +                      "label"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "required": {
        +                  "type": "boolean"
        +                },
        +                "source": {
        +                  "type": "string"
        +                },
        +                "type": {
        +                  "type": "string"
        +                }
        +              },
        +              "required": [
        +                "key",
        +                "type",
        +                "label",
        +                "hint",
        +                "required"
        +              ],
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "details_version": {
        +            "type": "integer"
        +          },
        +          "disturbs_note": {
        +            "type": "string"
        +          },
        +          "disturbs_prompt": {
        +            "type": "null"
        +          },
        +          "disturbs_zero": {
        +            "type": "boolean"
        +          },
        +          "every": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "days": {
        +                "type": "integer"
        +              },
        +              "litres": {
        +                "type": [
        +                  "integer",
        +                  "number"
        +                ]
        +              },
        +              "shots": {
        +                "type": "integer"
        +              }
        +            },
        +            "required": [],
        +            "type": [
        +              "null",
        +              "object"
        +            ]
        +          },
        +          "every_source": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "days": {
        +                "type": "string"
        +              },
        +              "litres": {
        +                "type": "string"
        +              },
        +              "shots": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [],
        +            "type": [
        +              "null",
        +              "object"
        +            ]
        +          },
        +          "guide": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "also_covers": {
        +                "type": "null"
        +              },
        +              "basis": {
        +                "type": "string"
        +              },
        +              "duration_minutes": {
        +                "type": [
        +                  "integer",
        +                  "null"
        +                ]
        +              },
        +              "duration_note": {
        +                "type": "null"
        +              },
        +              "id": {
        +                "type": "string"
        +              },
        +              "machine_alert": {
        +                "additionalProperties": true,
        +                "properties": {
        +                  "can_disable": {
        +                    "type": "null"
        +                  },
        +                  "clears": {
        +                    "type": [
        +                      "null",
        +                      "string"
        +                    ]
        +                  },
        +                  "counts": {
        +                    "type": "string"
        +                  },
        +                  "depends_on_setting": {
        +                    "type": "null"
        +                  },
        +                  "indicator": {
        +                    "type": "string"
        +                  },
        +                  "shown_as": {
        +                    "type": "string"
        +                  },
        +                  "source": {
        +                    "type": "string"
        +                  },
        +                  "threshold": {
        +                    "type": "null"
        +                  }
        +                },
        +                "required": [],
        +                "type": [
        +                  "object",
        +                  "null"
        +                ]
        +              },
        +              "market": {
        +                "type": "null"
        +              },
        +              "scope": {
        +                "type": "string"
        +              },
        +              "steps": {
        +                "type": "integer"
        +              },
        +              "title": {
        +                "type": "string"
        +              },
        +              "variant": {
        +                "type": "null"
        +              },
        +              "warnings": {
        +                "type": "integer"
        +              }
        +            },
        +            "required": [],
        +            "type": [
        +              "null",
        +              "object"
        +            ]
        +          },
        +          "kind": {
        +            "type": "string"
        +          },
        +          "label": {
        +            "type": "string"
        +          },
        +          "offset_integral": {
        +            "type": "boolean"
        +          },
        +          "offset_unit": {
        +            "type": "string"
        +          },
        +          "opened_by": {
        +            "type": "null"
        +          },
        +          "schedule": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "enabled": {
        +                "type": "boolean"
        +              },
        +              "every": {
        +                "additionalProperties": true,
        +                "properties": {
        +                  "days": {
        +                    "type": "integer"
        +                  },
        +                  "litres": {
        +                    "type": "number"
        +                  }
        +                },
        +                "required": [
        +                  "days",
        +                  "litres"
        +                ],
        +                "type": "object"
        +              },
        +              "muted_until": {
        +                "type": "string"
        +              }
        +            },
        +            "required": [],
        +            "type": [
        +              "null",
        +              "object"
        +            ]
        +          },
        +          "scheduled": {
        +            "type": "boolean"
        +          },
        +          "status": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "sub": {
        +            "type": "string"
        +          },
        +          "trigger": {
        +            "type": [
        +              "null",
        +              "string"
        +            ]
        +          },
        +          "value": {
        +            "type": "string"
        +          },
        +          "why": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "value",
        +          "kind",
        +          "label",
        +          "sub",
        +          "disturbs_zero",
        +          "every",
        +          "why",
        +          "disturbs_note",
        +          "offset_unit",
        +          "offset_integral",
        +          "scheduled",
        +          "opened_by",
        +          "details_version",
        +          "details_fields",
        +          "class",
        +          "status",
        +          "trigger",
        +          "every_source",
        +          "disturbs_prompt",
        +          "guide",
        +          "schedule"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "tasks",
        +    "due",
        +    "calibration",
        +    "sensitivity",
        +    "entries",
        +    "entries_total",
        +    "catalog_version",
        +    "computed_at",
        +    "catalog",
        +    "hardness"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / properties / machines / items / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "control_type",
        -  "basket_size_grams",
        -  "boiler_type",
        -  "notes",
        -  "prep_type",
        -  "prep_style",
        -  "archived",
        -  "built_in_grinder_id",
        -  "tools_list",
        -  "programs"
        -]New value: +[
        +  "id",
        +  "name",
        +  "control_type",
        +  "basket_size_grams",
        +  "boiler_type",
        +  "notes",
        +  "prep_type",
        +  "prep_style",
        +  "archived",
        +  "built_in_grinder_id",
        +  "catalog_id",
        +  "hardness_dh",
        +  "tools_list",
        +  "programs",
        +  "maintenance"
        +]
    • Addedlist_maintenance_due
    • Changedlog_maintenance12 fields changed
      • changedInput schema / properties / details / description
        Previous value: -"Fields specific to this task. Which ones a task takes is published as details_fields in the task catalog on list_grinders; a burr clean takes none"New value: +"Fields specific to this task. Which ones a task takes is published as details_fields on each task; a burr clean takes none"
      • changedInput schema / properties / equipment_kind / enum
        Previous value: -[
        -  "grinder"
        -]New value: +[
        +  "grinder",
        +  "machine"
        +]
      • addedInput schema / properties / guide_id
        Added value: +{
        +  "description": "Optional โ€” the id of the maintenance guide that was followed. Must be a guide for this task",
        +  "type": "string"
        +}
      • changedInput schema / properties / task / enum
        Previous value: -[
        -  "burr_clean"
        -]New value: +[
        +  "burr_clean",
        +  "backflush_water",
        +  "backflush_detergent",
        +  "descale",
        +  "group_gasket_replace",
        +  "shower_screen_clean",
        +  "shower_screen_replace",
        +  "group_head_wipe",
        +  "basket_portafilter_soak",
        +  "steam_wand_purge",
        +  "steam_wand_soak",
        +  "drip_tray_clean",
        +  "water_tank_clean",
        +  "water_filter_replace",
        +  "boiler_water_change",
        +  "lever_piston_seal_replace",
        +  "lever_lubricate",
        +  "milk_system_clean",
        +  "professional_service",
        +  "builtin_grinder_burr_clean",
        +  "builtin_grinder_burr_replace",
        +  "grinder_quick_clean",
        +  "grinder_cleaning_tablets",
        +  "burr_replace",
        +  "hopper_clean",
        +  "grounds_cup_clean",
        +  "bearing_lubricate",
        +  "gasket_seal_replace",
        +  "idle_rinse",
        +  "water_wash",
        +  "dishwasher",
        +  "filter_prime",
        +  "softener_regenerate",
        +  "other"
        +]
      • addedOutput schema / properties / deduped
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / entry / properties / details / additionalProperties
        Added value: +true
      • addedOutput schema / properties / entry / properties / details / properties
        Added value: +{
        +  "filter_id": {
        +    "type": "string"
        +  },
        +  "label": {
        +    "type": "string"
        +  },
        +  "product": {
        +    "type": "string"
        +  }
        +}
      • addedOutput schema / properties / entry / properties / details / required
        Added value: +[]
      • changedOutput schema / properties / entry / properties / details / type
        Previous value: -"null"New value: +[
        +  "null",
        +  "object"
        +]
      • addedOutput schema / properties / entry / properties / guide_id
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • changedOutput schema / properties / entry / required
        Previous value: -[
        -  "id",
        -  "equipment_kind",
        -  "equipment_id",
        -  "task",
        -  "performed_at",
        -  "disturbs_zero",
        -  "note",
        -  "offset_value",
        -  "offset_source",
        -  "offset_at",
        -  "evidence",
        -  "details",
        -  "details_version",
        -  "created_at",
        -  "details_known"
        -]New value: +[
        +  "id",
        +  "equipment_kind",
        +  "equipment_id",
        +  "task",
        +  "performed_at",
        +  "disturbs_zero",
        +  "note",
        +  "offset_value",
        +  "offset_source",
        +  "offset_at",
        +  "evidence",
        +  "details",
        +  "details_version",
        +  "created_at",
        +  "guide_id",
        +  "details_known"
        +]
      • changedOutput schema / required
        Previous value: -[
        -  "entry_id",
        -  "entry",
        -  "message"
        -]New value: +[
        +  "entry_id",
        +  "entry",
        +  "deduped",
        +  "message"
        +]
    • Changedregister_grinder1 field changed
      • addedInput schema / properties / catalog_id
        Added value: +{
        +  "description": "Optional โ€” the maintenance catalog model this is (the `id` of a catalog row, e.g. rancilio-silvia), when it was registered from the catalog. Its maintenance then comes from that model's researched record. \"none\" says it is not in the catalog.",
        +  "type": "string"
        +}
    • Changedregister_machine2 fields changed
      • addedInput schema / properties / catalog_id
        Added value: +{
        +  "description": "Optional โ€” the maintenance catalog model this is (the `id` of a catalog row, e.g. rancilio-silvia), when it was registered from the catalog. Its maintenance then comes from that model's researched record. \"none\" says it is not in the catalog.",
        +  "type": "string"
        +}
      • addedInput schema / properties / hardness_dh
        Added value: +{
        +  "description": "Optional โ€” the TOTAL hardness (GH) of the water this machine runs on, in ยฐdH (German degrees; ppm as CaCO3 รท 17.85), as a test strip reports it. Picks the band of a maker's hardness table for descaling and filter life",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
    • Changedset_maintenance_offset2 fields changed
      • addedOutput schema / properties / entry / properties / guide_id
        Added value: +{
        +  "type": "null"
        +}
      • changedOutput schema / properties / entry / required
        Previous value: -[
        -  "id",
        -  "equipment_kind",
        -  "equipment_id",
        -  "task",
        -  "performed_at",
        -  "disturbs_zero",
        -  "note",
        -  "offset_value",
        -  "offset_source",
        -  "offset_at",
        -  "evidence",
        -  "details",
        -  "details_version",
        -  "created_at",
        -  "details_known"
        -]New value: +[
        +  "id",
        +  "equipment_kind",
        +  "equipment_id",
        +  "task",
        +  "performed_at",
        +  "disturbs_zero",
        +  "note",
        +  "offset_value",
        +  "offset_source",
        +  "offset_at",
        +  "evidence",
        +  "details",
        +  "details_version",
        +  "created_at",
        +  "guide_id",
        +  "details_known"
        +]
    • Addedset_maintenance_schedule
    • Changedupdate_grinder1 field changed
      • addedInput schema / properties / fields / properties / catalog_id
        Added value: +{
        +  "description": "The maintenance catalog model this grinder is; \"none\" if it is not listed; null to unbind. list_grinders proposes one from the name under maintenance.catalog.match",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
    • Changedupdate_machine2 fields changed
      • addedInput schema / properties / fields / properties / catalog_id
        Added value: +{
        +  "description": "The maintenance catalog model this machine is; \"none\" if it is not listed; null to unbind. list_machines proposes one from the name under maintenance.catalog.match",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedInput schema / properties / fields / properties / hardness_dh
        Added value: +{
        +  "description": "The total hardness (GH) of the water this machine runs on, in ยฐdH; null to fall back to the water of its last shot",
        +  "type": [
        +    "number",
        +    "null"
        +  ]
        +}
  10. 10 tool updates
    • Changedlist_grinders33 fields changed
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / disturbs_note
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / epoch_at / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / epoch_id / type
        Previous value: -[
        -  "null",
        -  "integer"
        -]New value: +[
        +  "integer",
        +  "null"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / epoch_task
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / offset_at / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / offset_source / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / offset_value / type
        Previous value: -[
        -  "null",
        -  "integer"
        -]New value: +[
        +  "integer",
        +  "null"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / properties / untranslatable_recipe_count
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / calibration / required
        Previous value: -[
        -  "stale_recipe_count",
        -  "reference_recipe_id",
        -  "state",
        -  "epoch_id",
        -  "epoch_at",
        -  "offset_value",
        -  "offset_unit",
        -  "offset_source",
        -  "offset_at",
        -  "evidence"
        -]New value: +[
        +  "stale_recipe_count",
        +  "untranslatable_recipe_count",
        +  "reference_recipe_id",
        +  "state",
        +  "epoch_id",
        +  "epoch_task",
        +  "disturbs_note",
        +  "epoch_at",
        +  "offset_value",
        +  "offset_unit",
        +  "offset_source",
        +  "offset_at",
        +  "evidence"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / basis / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / done / type
        Previous value: -[
        -  "null",
        -  "integer"
        -]New value: +[
        +  "integer",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / every / type
        Previous value: -[
        -  "null",
        -  "integer"
        -]New value: +[
        +  "integer",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / ratio / type
        Previous value: -"integer"New value: +[
        +  "number",
        +  "integer"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / due / properties / burr_clean / properties / remaining / type
        Previous value: -[
        -  "null",
        -  "integer"
        -]New value: +[
        +  "integer",
        +  "null"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / details / additionalProperties
        Added value: +true
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / details / properties
        Added value: +{
        +  "from": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "components_spec": {
        +        "type": [
        +          "null",
        +          "string"
        +        ]
        +      },
        +      "nominal_step": {
        +        "type": [
        +          "number",
        +          "integer"
        +        ]
        +      },
        +      "setting_scheme": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "setting_scheme",
        +      "nominal_step",
        +      "components_spec"
        +    ],
        +    "type": "object"
        +  },
        +  "to": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "components_spec": {
        +        "type": [
        +          "null",
        +          "string"
        +        ]
        +      },
        +      "nominal_step": {
        +        "type": [
        +          "number",
        +          "integer"
        +        ]
        +      },
        +      "setting_scheme": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "setting_scheme",
        +      "nominal_step",
        +      "components_spec"
        +    ],
        +    "type": "object"
        +  }
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / details / required
        Added value: +[]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / details / type
        Previous value: -"null"New value: +[
        +  "object",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / evidence / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / note / type
        Previous value: -[
        -  "null",
        -  "string"
        -]New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / offset_at / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / offset_source / type
        Previous value: -[
        -  "string",
        -  "null"
        -]New value: +[
        +  "null",
        +  "string"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / entries / items / properties / offset_value / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / every / required
        Previous value: -[
        -  "days",
        -  "shots",
        -  "grams"
        -]New value: +[]
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / every / type
        Previous value: -"object"New value: +[
        +  "object",
        +  "null"
        +]
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / opened_by
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • addedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / properties / scheduled
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / grinders / items / properties / maintenance / properties / tasks / items / required
        Previous value: -[
        -  "value",
        -  "kind",
        -  "label",
        -  "sub",
        -  "disturbs_zero",
        -  "every",
        -  "why",
        -  "disturbs_note",
        -  "offset_unit",
        -  "offset_integral",
        -  "details_version",
        -  "details_fields"
        -]New value: +[
        +  "value",
        +  "kind",
        +  "label",
        +  "sub",
        +  "disturbs_zero",
        +  "every",
        +  "why",
        +  "disturbs_note",
        +  "offset_unit",
        +  "offset_integral",
        +  "scheduled",
        +  "opened_by",
        +  "details_version",
        +  "details_fields"
        +]
      • changedOutput schema / properties / grinders / items / properties / max_value / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • changedOutput schema / properties / grinders / items / properties / microns_per_step / type
        Previous value: -[
        -  "null",
        -  "integer"
        -]New value: +[
        +  "integer",
        +  "null"
        +]
      • changedOutput schema / properties / grinders / items / properties / min_value / type
        Previous value: -[
        -  "integer",
        -  "null"
        -]New value: +[
        +  "null",
        +  "integer"
        +]
      • changedOutput schema / properties / grinders / items / properties / nominal_step / type
        Previous value: -"integer"New value: +[
        +  "number",
        +  "integer"
        +]
      • changedOutput schema / properties / grinders / items / properties / notes / type
        Previous value: -"null"New value: +[
        +  "string",
        +  "null"
        +]
    • Changedlist_machines2 fields changed
      • changedOutput schema / properties / machines / items / properties / notes / type
        Previous value: -"null"New value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / machines / items / properties / tools_list / items
        Added value: +{
        +  "type": "string"
        +}
    • Changedlist_recipes2 fields changed
      • addedOutput schema / properties / recipes / items / properties / grind_reading / properties / epoch_tasks
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / recipes / items / properties / grind_reading / properties / untranslatable
        Added value: +{
        +  "type": "boolean"
        +}
    • Changedlist_shots1 field changed
      • changedOutput schema / properties / shots / items / properties / flavor_notes / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
    • Changedlog_maintenance2 fields changed
      • addedOutput schema / properties / entry / properties / details_known
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / entry / required
        Previous value: -[
        -  "id",
        -  "equipment_kind",
        -  "equipment_id",
        -  "task",
        -  "performed_at",
        -  "disturbs_zero",
        -  "note",
        -  "offset_value",
        -  "offset_source",
        -  "offset_at",
        -  "evidence",
        -  "details",
        -  "details_version",
        -  "created_at"
        -]New value: +[
        +  "id",
        +  "equipment_kind",
        +  "equipment_id",
        +  "task",
        +  "performed_at",
        +  "disturbs_zero",
        +  "note",
        +  "offset_value",
        +  "offset_source",
        +  "offset_at",
        +  "evidence",
        +  "details",
        +  "details_version",
        +  "created_at",
        +  "details_known"
        +]
    • Changedset_maintenance_offset7 fields changed
      • addedOutput schema / properties / entry / properties / details / additionalProperties
        Added value: +true
      • addedOutput schema / properties / entry / properties / details / properties
        Added value: +{
        +  "from": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "components_spec": {
        +        "type": "string"
        +      },
        +      "nominal_step": {
        +        "type": "integer"
        +      },
        +      "setting_scheme": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "setting_scheme",
        +      "nominal_step",
        +      "components_spec"
        +    ],
        +    "type": "object"
        +  },
        +  "to": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "components_spec": {
        +        "type": "null"
        +      },
        +      "nominal_step": {
        +        "type": "number"
        +      },
        +      "setting_scheme": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "setting_scheme",
        +      "nominal_step",
        +      "components_spec"
        +    ],
        +    "type": "object"
        +  }
        +}
      • addedOutput schema / properties / entry / properties / details / required
        Added value: +[]
      • changedOutput schema / properties / entry / properties / details / type
        Previous value: -"null"New value: +[
        +  "null",
        +  "object"
        +]
      • addedOutput schema / properties / entry / properties / details_known
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / entry / properties / evidence / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / entry / required
        Previous value: -[
        -  "id",
        -  "equipment_kind",
        -  "equipment_id",
        -  "task",
        -  "performed_at",
        -  "disturbs_zero",
        -  "note",
        -  "offset_value",
        -  "offset_source",
        -  "offset_at",
        -  "evidence",
        -  "details",
        -  "details_version",
        -  "created_at"
        -]New value: +[
        +  "id",
        +  "equipment_kind",
        +  "equipment_id",
        +  "task",
        +  "performed_at",
        +  "disturbs_zero",
        +  "note",
        +  "offset_value",
        +  "offset_source",
        +  "offset_at",
        +  "evidence",
        +  "details",
        +  "details_version",
        +  "created_at",
        +  "details_known"
        +]
    • Addedupdate_grinder
    • Addedupdate_machine
    • Addedupdate_scale
    • Addedupdate_water
  11. 14 tool updates
    • Changedcompute_age3 fields changed
      • addedInput schema / properties / bag_id
        Added value: +{
        +  "description": "A bag of that coffee (from list_beans' bags[]); null = its current bag",
        +  "type": [
        +    "integer",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / bag_id
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "bean_id",
        -  "roast_date",
        -  "age_days",
        -  "days_off_roast",
        -  "days_since_opened",
        -  "frozen_days_excluded",
        -  "effective_age_days",
        -  "rest_window",
        -  "verdict",
        -  "grams_remaining",
        -  "warnings"
        -]New value: +[
        +  "bean_id",
        +  "bag_id",
        +  "roast_date",
        +  "age_days",
        +  "days_off_roast",
        +  "days_since_opened",
        +  "frozen_days_excluded",
        +  "effective_age_days",
        +  "rest_window",
        +  "verdict",
        +  "grams_remaining",
        +  "warnings"
        +]
    • Changeddiagnose_preview2 fields changed
      • addedOutput schema / properties / bean_context / properties / bag_id
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / properties / bean_context / required
        Previous value: -[
        -  "bean_id",
        -  "bean_name",
        -  "roast_level",
        -  "effective_age_days",
        -  "dial_category"
        -]New value: +[
        +  "bean_id",
        +  "bag_id",
        +  "bean_name",
        +  "roast_level",
        +  "effective_age_days",
        +  "dial_category"
        +]
    • Changeddiagnose_shot2 fields changed
      • addedOutput schema / properties / bean_context / properties / bag_id
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / properties / bean_context / required
        Previous value: -[
        -  "bean_id",
        -  "bean_name",
        -  "roast_level",
        -  "effective_age_days",
        -  "dial_category"
        -]New value: +[
        +  "bean_id",
        +  "bag_id",
        +  "bean_name",
        +  "roast_level",
        +  "effective_age_days",
        +  "dial_category"
        +]
    • Changedget_dial_state10 fields changed
      • addedOutput schema / properties / active_coffee / properties / acidity
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / active_coffee / properties / arabica_pct
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / active_coffee / properties / bag
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "age_verdict": {
        +      "type": "string"
        +    },
        +    "archived": {
        +      "type": "integer"
        +    },
        +    "bag_notes": {
        +      "type": "string"
        +    },
        +    "bag_weight_g": {
        +      "type": "null"
        +    },
        +    "bean_id": {
        +      "type": "integer"
        +    },
        +    "best_by_date": {
        +      "type": "null"
        +    },
        +    "buy_date": {
        +      "type": "null"
        +    },
        +    "cost": {
        +      "type": "null"
        +    },
        +    "currency": {
        +      "type": "null"
        +    },
        +    "days_off_roast": {
        +      "type": "integer"
        +    },
        +    "days_since_opened": {
        +      "type": "null"
        +    },
        +    "ean": {
        +      "type": "null"
        +    },
        +    "effective_age_days": {
        +      "type": "integer"
        +    },
        +    "finished": {
        +      "type": "integer"
        +    },
        +    "frozen_at": {
        +      "type": "null"
        +    },
        +    "frozen_days_excluded": {
        +      "type": "integer"
        +    },
        +    "frozen_note": {
        +      "type": "null"
        +    },
        +    "frozen_storage": {
        +      "type": "null"
        +    },
        +    "grams_remaining": {
        +      "type": "null"
        +    },
        +    "id": {
        +      "type": "integer"
        +    },
        +    "opened_date": {
        +      "type": "null"
        +    },
        +    "qr_code": {
        +      "type": "null"
        +    },
        +    "roast_date": {
        +      "type": "string"
        +    },
        +    "state": {
        +      "type": "string"
        +    },
        +    "storage": {
        +      "type": "null"
        +    },
        +    "unfrozen_at": {
        +      "type": "null"
        +    },
        +    "weight_adjustment_g": {
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "bean_id",
        +    "roast_date",
        +    "buy_date",
        +    "opened_date",
        +    "best_by_date",
        +    "bag_weight_g",
        +    "weight_adjustment_g",
        +    "cost",
        +    "currency",
        +    "state",
        +    "finished",
        +    "frozen_at",
        +    "unfrozen_at",
        +    "frozen_storage",
        +    "frozen_note",
        +    "storage",
        +    "ean",
        +    "qr_code",
        +    "bag_notes",
        +    "archived",
        +    "days_off_roast",
        +    "days_since_opened",
        +    "frozen_days_excluded",
        +    "effective_age_days",
        +    "age_verdict",
        +    "grams_remaining"
        +  ],
        +  "type": "object"
        +}
      • addedOutput schema / properties / active_coffee / properties / body
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / active_coffee / properties / current_bag_id
        Added value: +{
        +  "type": "integer"
        +}
      • addedOutput schema / properties / active_coffee / properties / notes
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / active_coffee / properties / sweetness
        Added value: +{
        +  "type": "null"
        +}
      • changedOutput schema / properties / active_coffee / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "roaster",
        -  "origin",
        -  "variety",
        -  "roast_date",
        -  "roast_level",
        -  "process_type",
        -  "dial_category",
        -  "bag_notes",
        -  "rest_window_days_min",
        -  "rest_window_days_max",
        -  "state",
        -  "opened_date",
        -  "storage",
        -  "is_active",
        -  "weight_adjustment_g",
        -  "buy_date",
        -  "bag_weight_g",
        -  "cost",
        -  "currency",
        -  "decaffeinated",
        -  "bean_mix",
        -  "roast_range",
        -  "roast_custom",
        -  "roasting_type",
        -  "aromatics",
        -  "cupping_points",
        -  "rating",
        -  "favourite",
        -  "url",
        -  "ean",
        -  "qr_code",
        -  "co2e_kg",
        -  "attachments",
        -  "archived",
        -  "frozen_at",
        -  "unfrozen_at",
        -  "frozen_storage",
        -  "frozen_note",
        -  "best_by_date",
        -  "finished",
        -  "age_days",
        -  "days_off_roast",
        -  "days_since_opened",
        -  "frozen_days_excluded",
        -  "effective_age_days",
        -  "age_verdict",
        -  "grams_remaining"
        -]New value: +[
        +  "id",
        +  "name",
        +  "roaster",
        +  "origin",
        +  "variety",
        +  "roast_date",
        +  "roast_level",
        +  "process_type",
        +  "dial_category",
        +  "bag_notes",
        +  "rest_window_days_min",
        +  "rest_window_days_max",
        +  "state",
        +  "opened_date",
        +  "storage",
        +  "is_active",
        +  "weight_adjustment_g",
        +  "buy_date",
        +  "bag_weight_g",
        +  "cost",
        +  "currency",
        +  "decaffeinated",
        +  "bean_mix",
        +  "roast_range",
        +  "roast_custom",
        +  "roasting_type",
        +  "aromatics",
        +  "cupping_points",
        +  "rating",
        +  "favourite",
        +  "url",
        +  "ean",
        +  "qr_code",
        +  "co2e_kg",
        +  "attachments",
        +  "archived",
        +  "frozen_at",
        +  "unfrozen_at",
        +  "frozen_storage",
        +  "frozen_note",
        +  "best_by_date",
        +  "finished",
        +  "notes",
        +  "arabica_pct",
        +  "body",
        +  "acidity",
        +  "sweetness",
        +  "age_days",
        +  "days_off_roast",
        +  "days_since_opened",
        +  "frozen_days_excluded",
        +  "effective_age_days",
        +  "age_verdict",
        +  "grams_remaining",
        +  "current_bag_id",
        +  "bag"
        +]
      • addedOutput schema / properties / recent_shots / items / properties / bag_id
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / properties / recent_shots / items / required
        Previous value: -[
        -  "id",
        -  "pulled_at",
        -  "bean_id",
        -  "grinder_id",
        -  "machine_id",
        -  "program_id",
        -  "grind_label",
        -  "grind_components",
        -  "grind_position_value",
        -  "dose_g",
        -  "yield_g",
        -  "time_s",
        -  "flow_rate_gps",
        -  "finish_action",
        -  "drink_intent",
        -  "flavor_notes",
        -  "sensory_tags",
        -  "observations",
        -  "temp_taste",
        -  "rating",
        -  "verdict",
        -  "data_confidence",
        -  "temperature_c",
        -  "bloom_time_s",
        -  "first_drip_time_s",
        -  "beverage_g",
        -  "tds",
        -  "ey_pct",
        -  "water_id",
        -  "vessel_name",
        -  "vessel_weight_g",
        -  "favourite",
        -  "best_brew",
        -  "tasted",
        -  "taste_pending"
        -]New value: +[
        +  "id",
        +  "pulled_at",
        +  "bean_id",
        +  "grinder_id",
        +  "machine_id",
        +  "program_id",
        +  "grind_label",
        +  "grind_components",
        +  "grind_position_value",
        +  "dose_g",
        +  "yield_g",
        +  "time_s",
        +  "flow_rate_gps",
        +  "finish_action",
        +  "drink_intent",
        +  "flavor_notes",
        +  "sensory_tags",
        +  "observations",
        +  "temp_taste",
        +  "rating",
        +  "verdict",
        +  "data_confidence",
        +  "temperature_c",
        +  "bloom_time_s",
        +  "first_drip_time_s",
        +  "beverage_g",
        +  "tds",
        +  "ey_pct",
        +  "water_id",
        +  "vessel_name",
        +  "vessel_weight_g",
        +  "favourite",
        +  "best_brew",
        +  "tasted",
        +  "bag_id",
        +  "taste_pending"
        +]
    • Changedlist_beans25 fields changed
      • addedOutput schema / properties / beans / items / properties / acidity
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / arabica_pct
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / aromatics
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / bags
        Added value: +{
        +  "items": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "age_verdict": {
        +        "type": "string"
        +      },
        +      "archived": {
        +        "type": "integer"
        +      },
        +      "bag_notes": {
        +        "type": [
        +          "null",
        +          "string"
        +        ]
        +      },
        +      "bag_weight_g": {
        +        "type": [
        +          "integer",
        +          "null"
        +        ]
        +      },
        +      "bean_id": {
        +        "type": "integer"
        +      },
        +      "best_by_date": {
        +        "type": "null"
        +      },
        +      "buy_date": {
        +        "type": "null"
        +      },
        +      "cost": {
        +        "type": [
        +          "null",
        +          "integer"
        +        ]
        +      },
        +      "currency": {
        +        "type": [
        +          "null",
        +          "string"
        +        ]
        +      },
        +      "days_off_roast": {
        +        "type": "integer"
        +      },
        +      "days_since_opened": {
        +        "type": "null"
        +      },
        +      "ean": {
        +        "type": "null"
        +      },
        +      "effective_age_days": {
        +        "type": "integer"
        +      },
        +      "finished": {
        +        "type": "integer"
        +      },
        +      "frozen_at": {
        +        "type": "null"
        +      },
        +      "frozen_days_excluded": {
        +        "type": "integer"
        +      },
        +      "frozen_note": {
        +        "type": "null"
        +      },
        +      "frozen_storage": {
        +        "type": "null"
        +      },
        +      "grams_remaining": {
        +        "type": [
        +          "integer",
        +          "null"
        +        ]
        +      },
        +      "id": {
        +        "type": "integer"
        +      },
        +      "opened_date": {
        +        "type": "null"
        +      },
        +      "qr_code": {
        +        "type": "null"
        +      },
        +      "roast_date": {
        +        "type": "string"
        +      },
        +      "shots_remaining": {
        +        "type": "integer"
        +      },
        +      "shots_remaining_basis": {
        +        "type": "string"
        +      },
        +      "shots_remaining_dose_g": {
        +        "type": [
        +          "integer",
        +          "number"
        +        ]
        +      },
        +      "shots_remaining_sample": {
        +        "type": [
        +          "integer",
        +          "null"
        +        ]
        +      },
        +      "state": {
        +        "type": "string"
        +      },
        +      "storage": {
        +        "type": "null"
        +      },
        +      "unfrozen_at": {
        +        "type": "null"
        +      },
        +      "weight_adjustment_g": {
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "bean_id",
        +      "roast_date",
        +      "buy_date",
        +      "opened_date",
        +      "best_by_date",
        +      "bag_weight_g",
        +      "weight_adjustment_g",
        +      "cost",
        +      "currency",
        +      "state",
        +      "finished",
        +      "frozen_at",
        +      "unfrozen_at",
        +      "frozen_storage",
        +      "frozen_note",
        +      "storage",
        +      "ean",
        +      "qr_code",
        +      "bag_notes",
        +      "archived",
        +      "effective_age_days",
        +      "age_verdict",
        +      "grams_remaining",
        +      "days_since_opened",
        +      "days_off_roast",
        +      "frozen_days_excluded"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / beans / items / properties / best_by_date
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / body
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / buy_date
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / cupping_points
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / current_bag_id
        Added value: +{
        +  "type": [
        +    "integer",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / beans / items / properties / ean
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / frozen_at
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / frozen_note
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / frozen_storage
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / notes
        Added value: +{
        +  "type": [
        +    "null",
        +    "string"
        +  ]
        +}
      • addedOutput schema / properties / beans / items / properties / origin
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / origins / items / properties / elevation_max_m
        Added value: +{
        +  "type": "null"
        +}
      • changedOutput schema / properties / beans / items / properties / origins / items / required
        Previous value: -[
        -  "country",
        -  "region",
        -  "farm",
        -  "farmer",
        -  "variety",
        -  "processing",
        -  "elevation_m",
        -  "harvest",
        -  "percentage"
        -]New value: +[
        +  "country",
        +  "region",
        +  "farm",
        +  "farmer",
        +  "variety",
        +  "processing",
        +  "elevation_m",
        +  "elevation_max_m",
        +  "harvest",
        +  "percentage"
        +]
      • addedOutput schema / properties / beans / items / properties / qr_code
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / roasting_type
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / sweetness
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / unfrozen_at
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / url
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / variety
        Added value: +{
        +  "type": "null"
        +}
      • addedOutput schema / properties / beans / items / properties / weight_adjustment_g
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / properties / beans / items / required
        Previous value: -[
        -  "id",
        -  "name",
        -  "roaster",
        -  "roast_date",
        -  "roast_level",
        -  "state",
        -  "opened_date",
        -  "archived",
        -  "finished",
        -  "favourite",
        -  "decaffeinated",
        -  "bag_weight_g",
        -  "process_type",
        -  "dial_category",
        -  "rest_window_days_min",
        -  "rest_window_days_max",
        -  "storage",
        -  "bag_notes",
        -  "cost",
        -  "currency",
        -  "rating",
        -  "effective_age_days",
        -  "age_verdict",
        -  "grams_remaining",
        -  "days_since_opened",
        -  "days_off_roast",
        -  "frozen_days_excluded",
        -  "origins"
        -]New value: +[
        +  "id",
        +  "name",
        +  "roaster",
        +  "roast_level",
        +  "archived",
        +  "favourite",
        +  "decaffeinated",
        +  "process_type",
        +  "dial_category",
        +  "rest_window_days_min",
        +  "rest_window_days_max",
        +  "rating",
        +  "aromatics",
        +  "cupping_points",
        +  "roasting_type",
        +  "variety",
        +  "origin",
        +  "url",
        +  "notes",
        +  "arabica_pct",
        +  "body",
        +  "acidity",
        +  "sweetness",
        +  "roast_date",
        +  "buy_date",
        +  "opened_date",
        +  "best_by_date",
        +  "bag_weight_g",
        +  "weight_adjustment_g",
        +  "cost",
        +  "currency",
        +  "state",
        +  "finished",
        +  "frozen_at",
        +  "unfrozen_at",
        +  "frozen_storage",
        +  "frozen_note",
        +  "storage",
        +  "ean",
        +  "qr_code",
        +  "bag_notes",
        +  "effective_age_days",
        +  "age_verdict",
        +  "grams_remaining",
        +  "days_since_opened",
        +  "days_off_roast",
        +  "frozen_days_excluded",
        +  "current_bag_id",
        +  "bags",
        +  "origins"
        +]
    • Changedlist_recipes2 fields changed
      • addedOutput schema / properties / recipes / items / properties / roaster_name
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / properties / recipes / items / required
        Previous value: -[
        -  "id",
        -  "bean_id",
        -  "grinder_id",
        -  "machine_id",
        -  "program_id",
        -  "status",
        -  "grind_label",
        -  "grind_position_value",
        -  "dose_g",
        -  "target_yield_g",
        -  "target_time_s",
        -  "finish_action",
        -  "drink_intent",
        -  "profile",
        -  "locked_at",
        -  "bean_name",
        -  "grinder_name",
        -  "machine_name",
        -  "grind_reading"
        -]New value: +[
        +  "id",
        +  "bean_id",
        +  "grinder_id",
        +  "machine_id",
        +  "program_id",
        +  "status",
        +  "grind_label",
        +  "grind_position_value",
        +  "dose_g",
        +  "target_yield_g",
        +  "target_time_s",
        +  "finish_action",
        +  "drink_intent",
        +  "profile",
        +  "locked_at",
        +  "bean_name",
        +  "roaster_name",
        +  "grinder_name",
        +  "machine_name",
        +  "grind_reading"
        +]
    • Changedlist_shots3 fields changed
      • addedInput schema / properties / filters / properties / bag_id
        Added value: +{
        +  "description": "Filter by bag number (one purchase of a coffee)",
        +  "type": "integer"
        +}
      • addedOutput schema / properties / shots / items / properties / bag_id
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / properties / shots / items / required
        Previous value: -[
        -  "id",
        -  "pulled_at",
        -  "bean_id",
        -  "grinder_id",
        -  "machine_id",
        -  "program_id",
        -  "grind_label",
        -  "grind_components",
        -  "grind_position_value",
        -  "dose_g",
        -  "yield_g",
        -  "time_s",
        -  "flow_rate_gps",
        -  "finish_action",
        -  "drink_intent",
        -  "flavor_notes",
        -  "sensory_tags",
        -  "observations",
        -  "temp_taste",
        -  "rating",
        -  "verdict",
        -  "data_confidence",
        -  "temperature_c",
        -  "bloom_time_s",
        -  "first_drip_time_s",
        -  "beverage_g",
        -  "tds",
        -  "ey_pct",
        -  "water_id",
        -  "vessel_name",
        -  "vessel_weight_g",
        -  "favourite",
        -  "best_brew",
        -  "tasted",
        -  "bean_name",
        -  "taste_pending"
        -]New value: +[
        +  "id",
        +  "pulled_at",
        +  "bean_id",
        +  "grinder_id",
        +  "machine_id",
        +  "program_id",
        +  "grind_label",
        +  "grind_components",
        +  "grind_position_value",
        +  "dose_g",
        +  "yield_g",
        +  "time_s",
        +  "flow_rate_gps",
        +  "finish_action",
        +  "drink_intent",
        +  "flavor_notes",
        +  "sensory_tags",
        +  "observations",
        +  "temp_taste",
        +  "rating",
        +  "verdict",
        +  "data_confidence",
        +  "temperature_c",
        +  "bloom_time_s",
        +  "first_drip_time_s",
        +  "beverage_g",
        +  "tds",
        +  "ey_pct",
        +  "water_id",
        +  "vessel_name",
        +  "vessel_weight_g",
        +  "favourite",
        +  "best_brew",
        +  "tasted",
        +  "bag_id",
        +  "bean_name",
        +  "taste_pending"
        +]
    • Changedlog_shot1 field changed
      • addedInput schema / properties / bag_id
        Added value: +{
        +  "description": "Which bag of the coffee the shot came from; defaults to its current (open) bag. Bag numbers are on list_beans' bags[]",
        +  "type": [
        +    "integer",
        +    "null"
        +  ]
        +}
    • Addedmerge_beans
    • Addedregister_bag
    • Changedregister_coffee8 fields changed
      • addedInput schema / properties / acidity
        Added value: +{
        +  "description": "Free text; roasters usually say low, medium or high",
        +  "type": "string"
        +}
      • addedInput schema / properties / arabica_pct
        Added value: +{
        +  "description": "Percent arabica, 100 for a pure arabica; the rest robusta",
        +  "maximum": 100,
        +  "minimum": 0,
        +  "type": "number"
        +}
      • addedInput schema / properties / body
        Added value: +{
        +  "description": "Free text; roasters usually say low, medium or high",
        +  "type": "string"
        +}
      • addedInput schema / properties / notes
        Added value: +{
        +  "description": "The coffee's own description โ€” the roaster's tasting notes, the dialing approach that worked. Per bag notes go in bag_notes.",
        +  "maxLength": 4096,
        +  "type": "string"
        +}
      • addedInput schema / properties / origins / items / properties / elevation_max_m
        Added value: +{
        +  "description": "Upper end of an elevation range, e.g. 1980 for \"1800โ€“1980 m\"; elevation_m is the lower end",
        +  "type": "number"
        +}
      • addedInput schema / properties / sweetness
        Added value: +{
        +  "description": "Free text; roasters usually say low, medium or high",
        +  "type": "string"
        +}
      • addedOutput schema / properties / bag_id
        Added value: +{
        +  "type": "integer"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "status",
        -  "bean_id",
        -  "message"
        -]New value: +[
        +  "status",
        +  "bean_id",
        +  "bag_id",
        +  "message"
        +]
    • Addedupdate_bag
    • Changedupdate_bean7 fields changed
      • addedInput schema / properties / fields / properties / acidity
        Added value: +{
        +  "description": "Free text; roasters usually say low, medium or high",
        +  "type": "string"
        +}
      • addedInput schema / properties / fields / properties / arabica_pct
        Added value: +{
        +  "maximum": 100,
        +  "minimum": 0,
        +  "type": "number"
        +}
      • addedInput schema / properties / fields / properties / body
        Added value: +{
        +  "description": "Free text; roasters usually say low, medium or high",
        +  "type": "string"
        +}
      • addedInput schema / properties / fields / properties / notes
        Added value: +{
        +  "description": "The coffee's own description โ€” roaster tasting notes, the dialing approach. Replaces the stored value; the optional reason is appended instead.",
        +  "maxLength": 4096,
        +  "type": "string"
        +}
      • addedInput schema / properties / fields / properties / origins / items / properties / elevation_max_m
        Added value: +{
        +  "description": "Upper end of an elevation range; elevation_m is the lower end",
        +  "type": "number"
        +}
      • addedInput schema / properties / fields / properties / sweetness
        Added value: +{
        +  "description": "Free text; roasters usually say low, medium or high",
        +  "type": "string"
        +}
      • changedInput schema / properties / reason / description
        Previous value: -"Optional free-text note, appended to the bag notes as an ordinary line. Omit it and nothing is written."New value: +"Optional free-text note, appended as an ordinary line to the coffee's notes โ€” or to the current bag's bag_notes when the call changed only bag fields. Omit it and nothing is written."
    • Changedupdate_shot2 fields changed
      • addedInput schema / properties / fields / properties / bag_id
        Added value: +{
        +  "description": "Re-file the shot onto this bag; must be a bag of the shot's bean",
        +  "type": "integer"
        +}
      • changedInput schema / properties / fields / properties / bean_id / description
        Previous value: -"Re-file the shot onto this bean"New value: +"Re-file the shot onto this bean (its current bag, unless bag_id is also given)"
  12. 34 tool updates
    • First observedcompute_age
    • First observeddelete_shot
    • First observeddiagnose_preview
    • First observeddiagnose_shot
    • First observedget_dial_state
    • First observedget_kb_version
    • First observedget_rule
    • First observedget_stats
    • First observedgrinder_math
    • First observedkb_changelog
    • First observedlist_beans
    • First observedlist_grinders
    • First observedlist_machines
    • First observedlist_recipes
    • First observedlist_scales
    • First observedlist_shots
    • First observedlist_waters
    • First observedlock_recipe
    • First observedlog_maintenance
    • First observedlog_recommendation
    • First observedlog_shot
    • First observedregister_coffee
    • First observedregister_grinder
    • First observedregister_machine
    • First observedregister_program
    • First observedregister_scale
    • First observedregister_water
    • First observedset_active
    • First observedset_equipment_archived
    • First observedset_grinder_position
    • First observedset_maintenance_offset
    • First observedsuggest_next_step
    • First observedupdate_bean
    • First observedupdate_shot

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Tracks caffeine decay and predicts safe bedtimes using a half-life model. No external integrations needed, intake is passed as parameters.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Gives your AI a live picture of your home bar's spirits, liqueurs, juices, garnishes, equipment and glassware, so it can suggest cocktails you can actually make right now, propose substitutes, help use up open bottles before they turn, and keep a shopping list. Runs locally alongside a web UI where you and the AI read and write the same inventory, with fill levels, expiry dates and every change logged.
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources