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, typed or not
Section titled “Any file, typed or not”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:
- 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 claimsslos/*.yaml). - Otherwise, the most specific
path:pattern among the types in force for the record’s scope. - 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.
Built-in types
Section titled “Built-in types”| 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,agentandshared-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/v1name: findisplay: Financial servicesversion: 1.2.0publisher: frazertypes: [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}], orpacks: [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.
The type language
Section titled “The type language”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/v1name: riskdisplay: Riskgroup: workversion: 2served: [1, 2]storage: 2changes: - to: 2 why: "review_by becomes a date Fir checks, not free text" steps: - {map: {field: review_by, values: {"next quarter": "~"}}}path: risks/*.mdkey: {prefix: RISK, digits: 3} # RISK-007, numbered by the serverfields: # 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: errorstages: 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 |
Rules in CEL
Section titled “Rules in CEL”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.
Computed fields and status
Section titled “Computed fields and status”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 progressA 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 a type allows and requires
Section titled “Links a type allows and requires”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.
Cost, and no ceiling
Section titled “Cost, and no ceiling”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.
Versions: nothing set in rock
Section titled “Versions: nothing set in rock”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.
Layers and scope
Section titled “Layers and scope”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).
Make a type: three doors
Section titled “Make a type: three doors”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.
The editor
Section titled “The editor”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.yamlformat: record-type/v1name: prod-incidentdisplay: Production incidentextends: postmortemkey: {prefix: INC, digits: 4} # INC-0043, numbered by the serverfields: 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.
Paste YAML
Section titled “Paste YAML”Settings › Plans › Types › New type › Paste YAML, or upload a file, or fir type add --from <file>:
- Validate against the published schema, with line numbers.
- 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. - 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.
- Backtest on existing records and docs, and list what Adopt would do.
- Preview the form, the template and a rendered example record.
- 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/v1name: freeze-exceptionextends: decision # counts as a decision: In force, conflicts, history, precedentskey: {prefix: FX, digits: 4} # FX-0001, numbered by the serverpath: freeze/**/*.mdfields: 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.
Ask an agent
Section titled “Ask an agent”“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/**:
- 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.
- 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. - 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.
- 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.
Import from other tools
Section titled “Import from other tools”| 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 |
Everything in front of the agent
Section titled “Everything in front of the agent”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.
Commands
Section titled “Commands”fir type listfir type show prod-incidentfir type explain freeze-exception.yamlfir type test prod-incidentfir type add --from freeze-exception.yamlfir type adopt prod-incidentfir type resolve planfir pack listfir pack add acme/packs-fintech@1.2.0fir pack upgrade finfir record types --show riskfir record rules --type prod-incident --testMCP tools
Section titled “MCP tools”| 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.
Related
Section titled “Related”- Plan repositories: both homes, links and Why
- The planning flow: the record checks, plan checks and the cold review that run what a type declares
- Programs: levels and the program tree
- Decisions: the
decisiontype and effect kinds