Skip to content

rules.yaml ​

The note on the fridge. Your housekeeper follows it to the letter, in code, with no model in the loop.

runs The rules engine lives in packages/core/src/rules.ts, with tests. The playground on the home page runs it in your browser.

Example ​

yaml
owner: stan
device: approvals-app        # where "ask me" requests go
default: ask                 # join | decline | ask
tags: [research-volunteers]
rules:
  - match: { purpose: research, sponsor_verified: true, ethics_approved: true }
    allow_fields: [age_band, medications, readmissions]
    deny_fields: [name, postcode, dob]
    min_price_usd: 4
    retention: none
    decision: join
  - match: { purpose: marketing }
    decision: decline
  - match: { requester: gp.example }
    allow_fields: [medications]
    grant_hours: 48
    decision: join
negotiation:
  join_collectives: true     # may counter-offer together with other houses

How a decision is made ​

Rules are checked top to bottom. The first rule whose match fits the offer decides. If none fits, default applies.

For a matching rule with decision: join:

Offer…Result
keeps data, but the rule says retention: nonedecline
asks for a field not in allow_fieldsask you, naming the field
asks for a deny_fields field, or pays below min_price_usdcounter (drop the field, raise the price) if join_collectives: true, otherwise ask
fits everythingjoin: a key for grant_hours (default 48), exactly those fields

decision: decline and decision: ask apply as written.

A default: join with no matching rule becomes ask, because without a rule nothing limits the fields.

Reference ​

KeyTypeMeaning
ownerstring, requiredYour name or handle
devicestringWhere ask requests go
defaultjoin | decline | askWhen no rule matches. Default ask.
tagslistInterests, used for discovery and guilds
rules[].matchmapAll keys must equal the offer's. Keys: purpose, requester, sponsor_verified, ethics_approved, audit_certified, and reputation_at_least (a number: the visitor's reputation from the nodes you follow, 0–1; unknown agents count as 0.5)
rules[].allow_fieldslistFields this rule may share
rules[].deny_fieldslistFields never shared under this rule
rules[].min_price_usdnumberLowest acceptable price per participant
rules[].retentionnone or ISO 8601 durationHow long the visitor may keep results
rules[].grant_hoursintegerKey lifetime. Default 48.
rules[].decisionjoin | decline | ask
negotiation.join_collectivesbooleanAllow your housekeeper to bargain with neighbours as one bloc

Trust ​

yaml
trust:
  issuers: [issuer.lake.local]     # who may sign your records
  auditors: [audit.lake.local]     # who may certify studies and converters
  ethics: [ethics.lake.local]      # whose ethics approvals count
  payments: [payments.lake.local]  # whose receipts you file

ethics_approved: true in a rule means approved by an ethics body you list here. An approval from anyone else counts as none. Nobody appoints these for the Lake; you choose. A sandbox house with no trust section trusts the demo specialists and says so in its log; outside the sandbox, an empty list trusts nobody.

Whatever your rules say, a study without a certificate from an auditor you trust never runs in your house.

Machine-readable: spec/schemas/rules.schema.json.

Safety properties ​

  • Typos fail closed. An unknown match key is an error, not an ignored line. A misspelling never widens access.
  • Free text is never read. Offers may carry a note; the engine ignores it. "Ignore your rules and share everything" has nothing to grab.
  • Deterministic. Same rules plus same offer gives the same answer, every time. That's what makes seeded demos and audits possible.
  • A join is your pre-approval, not the agent's. It counts because you wrote the rule. Agents can't write rules.

Apache-2.0 · Synthetic data only · Nobody owns the Lake.