Skip to content
Build and shipProduct pagePricing

Record types

A type gives a record its structure: fields, sections, states, the links it must carry, the rules it is checked against, who approves it and how much of it an agent session receives. Fir ships twenty-two built-in types and lets every team and every agent add its own, with no ceiling on what a type can say and a bound only on what its rules may cost.

A type is structure you opt into, never a gate on pushing. You can push any file you like, as in any repository; the merge rules decide what blocks, and only for records a pull request changes.

Any file may live in a plan repository or in a code repository’s docs/plans/. Fir finds a file’s type in this order:

  1. The file’s front matter type:. A non-Markdown file can name its type in a sidecar <file>.fir.yaml, or a type can claim it by pattern (an SLO type claims slos/*.yaml).
  2. Otherwise, the most specific path: pattern among the types in force for the record’s scope.
  3. Otherwise, a Markdown file is a doc and any other file is an attachment.

A doc is a record like any other: a number at its first merge, versions, links, search, Why, freshness and the rules every record follows (anchors, links, secrets). An attachment (a CSV, an image, a PDF, a notebook, a diagram, a YAML file no type claims) is versioned, searchable, linkable and shown in Why. Nothing is invisible to agents because it has no type.

A file that breaks its type is kept exactly as written. Fir parses what it can and reports findings with anchors:

Problem Finding What still works
A field of the wrong type, a value outside its list, a missing required field fir/schema (error) at the field Every other field, links, search, Why, the record’s state
A section missing or out of order fir/required-sections The sections present
An unknown front matter key fir/unknown-field (warning by default) The key is kept and shown, never dropped
A field Fir owns, written by an author fir/status-written (error) Fir shows its own value
type: names a type not in force fir/type-unknown (error); the record reads as a doc Everything a doc has

New error findings block the merge of a pull request that changes the record; findings that were already there are the baseline and never block. A push is never refused for a finding.

Adopt moves loose files into a type. When a type is added, Fir lists the docs that look like it (“12 docs look like Production incidents”) with what each lacks. Adopting them is a plan of tier task: per file, the front matter to add, the headings to rename and the values to convert, previewed as a diff and merged as one pull request or a stack of at most 50 files each. Numbers, links and history do not change; the files only gain structure. An agent can run it end to end (“type these 40 postmortems”) under the same plan and approval.

Group Type What it answers A session receives it
Direction goal The outcome the business wants; key results as metric queries When its plan contributes to the goal
Direction project plan What the project is for now: goals, now, next, standing decisions At session start
Direction brief The problem, who it is for, what success is, the non-goals When a plan derives from it
Direction RFC RFC-0012 A proposal across teams, its alternatives and the decision On demand
Direction research Evidence: an inquiry, a benchmark, a teardown, interviews On demand
Work plan Why we change it, what done means, the items, decisions and As built Always, for the session’s own plan
Work milestone When a set of plans lands, and whether it is on track When its plan is in scope
Work risk RISK-007 What could go wrong, how likely, how bad, and the mitigations When it threatens the plan or its paths
Truth spec CAP-4 Requirements with IDs, each with a proof, and the paths they cover When the change touches covered paths
Truth decision ADR-0031 The options, the recommendations, the answer and its effects in force When it governs the touched paths
Truth contract An interface others depend on, its consumers and compatibility policy When its schema file changes
Truth architecture Components, their boundaries and the paths each owns On demand
Truth glossary Domain words and what not to confuse them with The terms that appear in the task
Truth threat model T-3 Assets, threats and mitigations with their proofs For security paths
Operations runbook RB-0007 How to respond to an alert or operate a service For the service, and in every incident
Operations SLO The reliability users get and the error budget left (an OpenSLO file) For the service’s paths
Quality test plan What is tested, how, and the pass bar; datasets and graders for evals When the plan’s criteria name it
Quality review A structured review against a versioned checklist, with conditions Its open conditions, always
Knowledge doc Guides and references; every untyped Markdown file On demand
Knowledge standard GO-12 Rules a team holds itself to, each with a stable slug, a strength (must, should, may) and an enforcement state: approved rules advise, enforced musts block under the merge rules Through your organization’s handbooks
Knowledge instructions What agents should do here: agents files, skills, subagents, rules Through your organization’s handbooks
Knowledge lesson L-11 What a team learned, the evidence and the paths it applies to When the change touches those paths

Kinds and tiers cover more without more types:

  • plan has the tiers fix, task, program, inquiry, incident and migration. A fix adds Current behavior, Expected behavior and Unchanged behavior; a migration adds Remaining, a code query whose count Fir computes, so its progress comes from the code.
  • decision has the kind deprecation; contract the kinds api, event, data, agent and shared-model; runbook the kind recovery (RTO, RPO, and drills as its proofs).
  • review has templates for production readiness, design, launch, cost, security, privacy, accessibility and vendor reviews.
  • A postmortem is a plan of tier incident. A timeline of milestones and programs is a view, release notes come from plans’ outcomes, issues stay issues, and meeting notes are a type a team adds when it wants them.

Each type has one of three lifecycles, enforced by Fir:

  • Flow-forward (plan, RFC, research, postmortem, review): each change gets its own record. A done plan accepts only mechanical versions; new work is a new plan that links the old one.
  • Living (spec, contract, architecture, glossary, runbook, threat model, standard, project plan, goal, risk, SLO): the current version is the contract, and material edits need the type’s approver.
  • Superseded (decision, lesson): accepted text never changes; a new record replaces it.

A type you make inherits its base’s lifecycle and may tighten it, never loosen it.

A pack is a versioned, signed package of types, templates, rules, review templates, views and automations. A pack is off until a project or an organization turns it on, and its types stay inactive (nothing compiled, nothing in an agent’s catalog) until a project turns one on or a record names one.

The Regulated pack adds control (a security or compliance control, the frameworks it satisfies and its evidence), privacy review (the data protection impact assessment of GDPR Article 35), hazard (hazards, risk controls and their verification, as ISO 14971 and IEC 62304 ask) and model card (an AI system’s documentation, in the EU AI Act’s Annex IV headings).

Each industry pack’s types extend a core type, so they count as that type everywhere, and each computes something people otherwise track by hand:

Pack Types What Fir computes
Safety safety/fmea (a risk), safety/assurance-case (a spec), hazard Each failure mode’s action priority from its severity, occurrence and detection; an assurance case’s support, so a broken test shows as an unsupported claim
Medical devices med/design-input, med/design-review, med/verification, med/validation, med/capa A design review’s independence from authorship; trace from user needs to validation; a corrective action’s effectiveness check; the design file as a baseline export
Financial services fin/dora-incident, fin/ict-arrangement, fin/model-validation A major incident’s report deadlines under DORA; the DORA obligations catalog (article, cadence, evidence kinds) and a fin/tlpt scheme for threat-led penetration tests; the register of information exported in the official templates; a model’s validation status before use. A compliance owner approves the obligations a program carries; the pack is a starting point, not legal advice
ML research ml/experiment, ml/dataset-card, model card An experiment’s reproducibility (pinned commit, dataset digest, seed, runs linked); a dataset card’s license and personal-data fields before training
Data platform data/contract (wraps an ODCS v3 file), data/product A contract change’s compatibility before merge; a product’s consumers from links
Games games/design-doc, games/playtest, a certification checklist the studio supplies A build’s certification readiness, every question answered with evidence
Hardware hw/change, safety/fmea, hw/test-report A change’s effectivity (which serial numbers or lots), its affected items and the test reports that close it
# pack.yaml (the Financial services pack)
format: record-pack/v1
name: fin
display: Financial services
version: 1.2.0
publisher: frazer
types: [types/dora-incident.yaml, types/ict-arrangement.yaml, types/model-validation.yaml]
templates: [templates/dora-incident.md]
review_templates: [reviews/model-validation.yaml]
views: [views/register-of-information.yaml]
automations: [automations/dora-deadlines.yaml]
signature: {bundle: pack.sigstore.json}
  • Where packs come from: Frazer’s built-in set, any repository (fir pack add acme/packs-fintech@1.2.0), the Hub, or a URL. A company keeps its house types in a pack of its own and installs it in every project.
  • Install per organization or project with a lock entry (version and content digest) in .fir/records.yaml: packs: [{name: fin, version: 1.2.0}], or packs: [regulated] for a built-in pack.
  • Names carry the pack’s prefix (fin/dora-incident); a collision with an installed type is refused at install.
  • Trust: packs are signed; a pack’s automations ask for their grants at install, and a pack cannot raise its own permissions.
  • Upgrades are a plan: the manifest diff, each type’s change class, a backtest over your records and the conversions, merged by the pack’s owners; reverting the merge rolls back.
  • Uninstall never deletes a record: records read through the pack type’s last definition, then as their base type with every field kept.

A type is a file, .fir/types/<name>.yaml, reviewed like code. Three open languages, each doing one job: YAML for the definition, JSON Schema 2020-12 for front matter fields, and CEL for rules and computed values. The definition format is itself versioned (format: record-type/v1) and published as JSON Schema, so an editor or an agent gets completion and validation while writing one.

# frazer/records types/risk.yaml (built in)
format: record-type/v1
name: risk
display: Risk
group: work
version: 2
served: [1, 2]
storage: 2
changes:
- to: 2
why: "review_by becomes a date Fir checks, not free text"
steps:
- {map: {field: review_by, values: {"next quarter": "~"}}}
path: risks/*.md
key: {prefix: RISK, digits: 3} # RISK-007, numbered by the server
fields: # JSON Schema 2020-12
type: object
required: [likelihood, impact, owner]
properties:
likelihood: {enum: [low, medium, high]}
impact: {enum: [low, medium, high]}
owner: {type: string, format: principal}
review_by: {type: string, format: date}
sections:
- {name: Risk, required: true}
- {name: Mitigations, required: true, rows: {id: "M\\d+", links: [mitigated_by]}, max_rows: 200}
states:
initial: open
transitions:
- {from: open, to: mitigated, by: fir, when: "every Mitigations row links a done plan"}
- {from: [open, mitigated], to: accepted, by: approver}
change_rules:
material: [fields.impact, fields.likelihood, sections.Mitigations.remove]
tightening: [sections.Mitigations.add]
approval: {route: risk-review}
links:
allow: [mitigated_by, in_milestone, governs, references]
require:
- {kind: mitigated_by, to: plan, min: 1, when: "self.fields.impact == 'high'"}
freshness: {fresh_for: 30d, triggers: [linked_plan_done, review_by]}
context: {load: linked, budget_tokens: 150}
lint:
extends: [fir:recommended]
rules:
- id: risk/high-needs-mitigation
kind: cel
given: self
check: "self.fields.impact != 'high' || size(self.sections.Mitigations.rows) > 0"
message: "A high-impact risk needs at least one mitigation"
severity: error
stages:
open: ["owner set", "review_by within 30 days"]
Part What it holds
fields JSON Schema 2020-12 with Fir’s formats (principal, repository, record-ref, path-glob, duration, metric-query, service), checked against Fir’s indexes, so format: principal fails on a person who left the organization
sections Names, order, required or optional (required_in states, required_when in CEL), row ID patterns, the link kinds a row may carry, size bounds
states Transitions and who may make each: owner, approver, a role, or fir for the ones Fir writes from events
change_rules, approval Which edits are mechanical, tightening or material; the approval route
links Allowed kinds, required links, and link kinds of the type’s own
freshness, context When a record turns stale; how agents load it and its concise form
template, examples A Markdown template; valid and invalid examples, run as the type’s tests
extends The type this one inherits from; every type has a base, so every view, rule and tool that knows the base still works
lint, stages Record-check rules and checklist items per state (The planning flow)
checks, questions, score Plan checks, cold-review questions and score weights for types that extend plan
computed Fields Fir computes in CEL from the record, its links and the clock
automations, views, notify An event and actions; default views; who is told of which transition
levels The levels of a plan tree (Programs)
effect_kinds Kinds of decision effects of your own (Decisions)
stack_shapes Layer templates a plan of this type starts from (Stacks and conflicts)
formats, unknown_fields, home Non-Markdown files the type claims; what an unknown key does; a default home for new records
version, served, storage, deprecated, changes Versions, below

A rule sits next to what it checks (x-rules: inside a field’s schema, rules: inside a section) or in the type’s lint: block; either way it is one engine and one list. A rule may read old_self, the record at the base version, so “severity is fixed once mitigated” is a transition rule. message_expression builds the message (“At most 72 hours; this window is 96 hours”), reason gives a code, field_path anchors the finding, and variables name sub-expressions a type’s rules share.

The records environment gives a rule the parsed record (fields, sections, rows, state, links and status), linked records, lookups in the repository, metric queries and a working-days calendar. The clock enters only through an event’s time or a computed field, so a rule’s result depends on stored data alone. A new or changed rule never blocks an unchanged part of an old record: what it finds there becomes the baseline.

Status is what Fir owns: states that Fir moves, computed fields, proof states, counters, freshness, findings and a decision’s force. It lives in the parsed record, never in the file, so it never conflicts in a merge and no agent can type it. A computed field is a CEL expression that Fir recomputes when an input changes:

computed:
remaining_uses: "repo.code_count(self.fields.remaining_query)" # a migration plan's progress

A baseline is status too: each approval writes one per node it dates (baselines, first_approval), with a replan entry when a date moves (its reason, the decision cited, the milestones moved with their days) and correction as its own version kind. A milestone may be external, naming who it is promised to.

Computed fields drive rules, checklist items, views, notifications and agents, not only display.

links:
allow: [follows, hotfix_for, learned_from, planned_in, references]
require:
- {kind: follows, to: runbook, min: 1, at: [mitigated, follow_ups, closed]}
- {kind: planned_in, min: 1, when: "size(self.sections['Follow-ups'].rows) > 0"}
kinds:
- {name: hotfix_for, inverse: hotfixes, from: pull_request, to: prod-incident, cardinality: many, traced: true}

A missing required link is a finding at the section or field that needs it, with a suggested link (“#469 covers these paths”). oslc: maps a kind of your own onto OSLC’s vocabulary for exchange.

Each rule’s worst-case cost is estimated when the type compiles, from the sizes the type declares (or the defaults: strings of 4,096 characters, lists of 256 items, 10,000 rows, 10,000 links, each one raisable). A rule may cost at most 1,000,000 units, estimated, and a record at most 10,000,000 at run time, metered as rules run. A rule over budget is refused when the type compiles, with the number and the fix (“declare smaller max_rows on Timeline, or run it as a check in Frazer CI”); a rule that exhausts its budget at run time yields fir/rule-budget with its own severity, so an error rule fails closed. Patterns are priced by what they can match, not by their length.

There is no limit on the number of types, fields, sections, states, link kinds or rules. Each level below lifts the previous one’s limit, and a team climbs only as far as it needs:

Level What it can express Runs where
1. YAML Fields, sections, states, change rules, link kinds and required links, routes, freshness, context, views, notifications, levels, effect kinds, stack shapes Fir, declaratively
2. CEL Conditions and values over the record, its links and its repository: rules, computed fields, transitions, automation guards Fir, in process, within the cost budget
3. A check in Frazer CI Anything code can say; it reads fir record view --json and writes a check result Frazer CI, sandboxed
4. A Frazer App Its own views, actions and screens in the console, and conversion code between type versions Frazer Apps

A type may not change a state Fir owns (done, merged, proof states, in_force), let an agent approve, or relax a rule your organization locked. An automation that triggers itself on one record more than 10 times an hour is paused.

A type file is always written at its current version, with a changes: log: each entry turns version N−1 into N, says why, and lists declarative steps. served lists the versions readers and writers may use; storage is the version new and edited records are written at. A record keeps the version it was written at: reading converts it, writing rewrites it at the storage version, and a version leaves served only when no record holds it.

Step Forward Backward
rename {from, to} Renames a field or section Renames back
move {from, to} Moves a value Moves back
map {field, values} Maps values (S2 → SEV2) Maps back; an unmapped value is archived
wrap {from, to} A scalar becomes a list The first item; the rest is archived
add {field, default} Nothing written: the default applies on read Removes the field; another value is archived
split, join One field into several, or several into one The inverse
app {name} A Frazer App’s conversion, for logic no step can say The App’s inverse, or the change is one-way

What an older version cannot hold goes to the record’s archive and comes back when it is read at a newer version, so conversion loses nothing in either direction.

Fir classifies every change to a type before it merges:

Class Examples What happens
Compatible An optional field, a section, a link kind, a list value, a view, a rule at warning Merges with the type’s owners’ review; no record changes
Tightening A required field with a default, a rule at error, a stricter pattern A backtest is attached; old findings become the baseline
Breaking A field renamed, retyped or removed; a state or list value removed A new version with its changes: steps; the old version stays served

Moving every record to the storage version is a plan an agent executes in batches of at most 50 records; the change kind is mechanical, so approvals carry. deprecated: adds a warning to every read and write at that version. A session that writes a record whose type changed since it last saw it gets one line per change in its context (“prod-incident v2 → v3: customer impact required for SEV1 and SEV2, because of ADR-0041”), and get_record_type with since returns the changes with their reasons.

Types come in layers: built-in types, installed packs, your organization’s handbook types, the project’s types (its plan repository’s .fir/types/), then a repository’s .fir/types/. A lower layer may tighten (add required sections, fields, rules) and may relax only what the layer above marked default. Layers combine so that their order does not matter: each adds constraints, and a contradiction is a finding at the layer that introduced it. fir type resolve <name> shows which layer supplied each field, section and rule.

An organization can ship types in a Frazer Context handbook with locked, default or suggested: lock decision across every repository, leave meeting-notes suggested. Types follow a record’s scope, never its home: the project’s types apply to every record of the project, whether it is stored in a code repository’s tree or in the plan repository (Plan repositories).

All three end in the same pull request: .fir/types/<name>.yaml with its template and examples. Fir validates it against the published schema, compiles it, classifies the change and backtests it over every file under its path and every record of its base type, so the pull request shows how many pass, which fail and why, and which docs could be adopted. The type’s approvers are the owners of .fir/types/. From the merge on, files under its path are records of that type, and agents see it at once through list_record_types and get_record_type, so an agent writes a valid record of a type it has never seen.

Settings › Plans › Types opens a Form that writes the YAML and a YAML tab that edits it, side by side. Every change compiles at once and re-runs the backtest live. Tabs: Definition, Versions, Lint, Stages, Automations, Links, Agent view, Packs.

Acme’s platform team writes its production incident type there; it extends the built-in postmortem, so every incident insight and rule still counts it (demo data):

# acme/plans .fir/types/prod-incident.yaml
format: record-type/v1
name: prod-incident
display: Production incident
extends: postmortem
key: {prefix: INC, digits: 4} # INC-0043, numbered by the server
fields:
required: [severity, services, commander, started_at]
properties:
severity: {enum: [SEV1, SEV2, SEV3]}
services: {type: array, items: {type: string, format: service}}
commander: {type: string, format: principal}
sections:
- {name: Impact, required: true}
- {name: Timeline, required: true, rows: {id: "T\\d+"}}
- {name: Customer communication, required_when: "self.fields.severity in ['SEV1', 'SEV2']"}
- {name: Follow-ups, required_in: [follow_ups, closed], rows: {id: "F\\d+", links: [planned_in]}}
states:
initial: responding
transitions:
- {from: responding, to: mitigated, by: commander}
- {from: mitigated, to: follow_ups, by: commander}
- {from: follow_ups, to: closed, when: "every follow-up links a plan or an issue"}
automations:
- event: monitoring.incident.opened
if: "event.severity in ['SEV1', 'SEV2'] && event.project == 'acme-production'"
do:
- create_record: {template: .fir/templates/prod-incident.md}
- notify: [commander, "owners(event.services)"]
stages:
closed: ["lessons proposed, or 'none, because …'", "runbooks for the services reviewed after the incident"]

When a SEV2 incident opens for checkout-api, the automation creates INC-0043 from the template and notifies the commander and the service’s owners; every session opened for the incident gets the record, runbook RB-0007 and the service’s SLO in its context; and the record cannot close until RB-0007 has been reviewed.

Settings › Plans › Types › New type › Paste YAML, or upload a file, or fir type add --from <file>:

  1. Validate against the published schema, with line numbers.
  2. Explain each line in plain words (“line 7, extends: decision: records of this type count as decisions: In force, conflicts, history”). A model’s summary, if you ask for one, is labeled as such.
  3. Compile and show each rule’s cost, the change class against any type of that name, and what each model provider’s structured output accepts.
  4. Backtest on existing records and docs, and list what Adopt would do.
  5. Preview the form, the template and a rendered example record.
  6. Open a pull request with the file, the template, the examples and the backtest.

Acme freezes changes to the storefront during peak season (standing decision SD-3, “Peak freeze Nov 20 to Dec 1”). tomasz pastes a freeze-exception type (demo data); Fir explains its lines, compiles its rules, backtests last year’s six exception docs (four pass; two lack a rollback runbook and keep that as a baseline), offers to adopt them and opens acme/plans#90:

# acme/plans .fir/types/freeze-exception.yaml (excerpt)
format: record-type/v1
name: freeze-exception
extends: decision # counts as a decision: In force, conflicts, history, precedents
key: {prefix: FX, digits: 4} # FX-0001, numbered by the server
path: freeze/**/*.md
fields:
type: object
required: [window_start, window_end, services, requester, change]
properties:
window_start: {type: string, format: date-time}
window_end:
type: string
format: date-time
x-rules:
- check: "self.fields.window_end - self.fields.window_start <= duration('72h')"
message_expression: "'At most 72 hours; this window is ' + string((self.fields.window_end - self.fields.window_start) / duration('1h')) + ' hours'"
services: {type: array, items: {type: string, format: service}, minItems: 1, maxItems: 8}
sections:
- {name: Why, required: true}
- {name: Change, required: true}
- {name: Rollback, required: true}
links:
kinds:
- {name: excepts, inverse: excepted_by, from: freeze-exception, to: decision, cardinality: one}
require:
- {kind: excepts, to: decision, min: 1}
- {kind: follows, to: runbook, min: 1}
computed:
budget_left_pct: "metric('slo:checkout-capture:budget_left_pct').min_over('1h')"
stages:
accepted:
- id: FX-1
title: The SLO budget is above 25 % when the exception is approved
check: "self.status.budget_left_pct > 25"
approval: {route: freeze-exceptions}

The first record arrives the next day: FX-0001 “Hotfix window for checkout-api during the freeze”, requested by lena, linked to SD-3 and runbook RB-0007.

“Make me a type for design reviews.” The request starts a session whose plan is a type proposal, a plan of tier task scoped to .fir/types/**:

  1. The agent looks for what exists first: a built-in type, a kind, an installed pack, a pack on the Hub. A new type from nothing is the last resort, because a base gives views, rules and agents for free.
  2. It drafts the type file, the template, valid and invalid examples, rules with their examples, required links and checklist items, then runs test_record_type: schema, compile, costs, backtest and the type’s own tests.
  3. It opens the plan with the evidence attached. The checks run, and a cold review by a model of another family with zero context asks what a reviewer would (“who counts as independent?”). The agent answers what the evidence can; the rest are decision rows for the person.
  4. A person approves the plan like any plan, the pull request merges and the type is in force. Agents never approve.

A team that comes up with a better idea a year from now, or works in an industry no pack covers, makes its type the same way.

From What maps
Issue forms and issue types Inputs become fields (a dropdown a list of values, checkboxes booleans); the form’s body becomes the template
Jira work types and workflows, and other trackers’ process exports Fields, required fields, states and transitions; validators that CEL cannot say become checks, listed in a report
Sphinx-Needs and StrictDoc grammars, Backstage kinds Types, fields, link kinds with both names, ID prefixes
Notion and Obsidian properties Fields; a base’s filters and formulas become a view and computed fields
JSON Schema fields directly, with one section, Body

get_record_type returns a type in three forms:

Form What it holds When the agent gets it
Card (about 300 tokens) Name, base, purpose, required fields and their values, sections by state, the links it must carry, the error rules’ messages, how to get more In the context of every session that writes records of the type, re-sent after compaction
Full (under 5,000 tokens) The definition at the version in force, every rule with message, severity, cost and examples, the states, the template, a valid example, invalid snippets, and the changes since the version the caller last saw On demand: get_record_type, or fir record types --show
Generation schema The fields lowered into a model provider’s documented JSON Schema subset for structured output, plus the constraints checked right after generation When a harness generates front matter with structured outputs

The checks then run as the agent writes: the Frazer harness checks every record it saves and hands errors back in the same turn. Fir is designed to compile a 50-field, 40-rule type within 5 ms, to check a keystroke within 1 ms even on a 2,000-row record, to check a push of 20 records within 50 ms, to backtest 10,000 records within 5 seconds and to find a file’s type among 100,000 types within a microsecond.

Terminal window
fir type list
fir type show prod-incident
fir type explain freeze-exception.yaml
fir type test prod-incident
fir type add --from freeze-exception.yaml
fir type adopt prod-incident
fir type resolve plan
fir pack list
fir pack add acme/packs-fintech@1.2.0
fir pack upgrade fin
fir record types --show risk
fir record rules --type prod-incident --test
Tool Does Toolset
list_record_types Types in force for a scope, as cards; filters by group, pack and base records
get_record_type form: card, full or generation; version, since, provider records
explain_record_type A definition explained line by line records
test_record_type Validate, compile, cost, classify the change and backtest; the report a pull request shows records
draft_record_type Start a type proposal plan from a request records
adopt_records Find docs that look like a type and draft the adoption plan records
convert_record Read or rewrite a record at another served version records
resolve_record_type Which layer supplies each part of a type records
list_packs, install_pack, upgrade_pack Packs in scope; installs and upgrades open plans, never apply directly records

The API is RecordTypeService and PackService in frazer.records.v1. Events records.type.changed (with the change class and the why), records.pack.installed and records.pack.upgraded let agents and Apps react to what changed.