# gbrain-base — the universal starter pack
#
# v0.38: reproduces today's hardcoded behavior byte-for-byte. Every brain
# inherits gbrain-base via `extends: gbrain-base` unless it explicitly
# opts out (`extends: null`). Existing brains see ZERO change after upgrade.
#
# Generated by scripts/generate-gbrain-base.ts from the source constants:
#   - src/core/markdown.ts::inferType (path prefix → type)
#   - src/core/link-extraction.ts::inferLinkType (verb regexes)
#   - src/core/link-extraction.ts::FRONTMATTER_LINK_MAP (field → verb)
#   - src/core/types.ts::ALL_PAGE_TYPES (the seed types)
#
# Determinism: codegen output is sorted lex-stable per primitive and per
# field. Re-running `bun scripts/generate-gbrain-base.ts` must produce
# byte-identical output. CI-pinned via
# test/regressions/gbrain-base-codegen-determinism.test.ts.
#
# Aliases: empty by default. v0.38 ships gbrain-base with NO alias graph
# edges so existing search behavior is unchanged. Users opt into alias
# relationships via `gbrain schema review-candidates` or by editing their
# own pack manifest. Codex F8 + E8 — no implicit primitive-sibling
# expansion.

api_version: gbrain-schema-pack-v1
name: gbrain-base
version: 1.0.0
description: Universal starter pack reproducing pre-v0.38 hardcoded behavior
gbrain_min_version: 0.38.0
extends: null
borrow_from: []

# Closed enum of {fact, take, bet, hunch} — the original v41/v48 CHECK
# constraint values. Migration v80 dropped the DB constraint; runtime
# validation reads this list. Schema packs that extend gbrain-base can
# add kinds (e.g. {finding, hypothesis} for research-state) by declaring
# their own takes_kinds.
takes_kinds:
  - fact
  - take
  - bet
  - hunch

# Page types — ORDERED BY inferType PRIORITY (NOT ALL_PAGE_TYPES order).
# Wiki subtypes + writing scan FIRST because they're stronger signals than
# ancestor directories (e.g. projects/blog/writing/essay.md → writing,
# not project). This mirrors the pre-v0.38 hardcoded order in
# src/core/markdown.ts::inferType. The
# test/regressions/gbrain-base-equivalence.test.ts parity gate pins it.
#
# Each entry: primitive (defaults source), path_prefixes (inferType
# mapping), aliases (empty by default — opt-in via user pack),
# extractable (facts-eligible), expert_routing (whoknows/find_experts
# candidate).
page_types:
  # Stronger-signal types first (override ancestor-directory matches).
  - name: writing
    primitive: media
    path_prefixes:
      - writing/
    aliases: []
    extractable: true
    expert_routing: false

  - name: analysis
    primitive: media
    path_prefixes:
      - wiki/analysis/
    aliases: []
    extractable: false
    expert_routing: false

  - name: guide
    primitive: media
    path_prefixes:
      - wiki/guides/
      - wiki/guide/
    aliases: []
    extractable: false
    expert_routing: false

  - name: hardware
    primitive: media
    path_prefixes:
      - wiki/hardware/
    aliases: []
    extractable: false
    expert_routing: false

  - name: architecture
    primitive: media
    path_prefixes:
      - wiki/architecture/
    aliases: []
    extractable: false
    expert_routing: false

  # Ancestor-directory types.
  - name: concept
    primitive: concept
    path_prefixes:
      - wiki/concepts/
      - wiki/concept/
    aliases: []
    # v0.41.11+ — concepts ARE knowledge: their bodies define the
    # concept, so the facts extractor should mine them like writing/
    # source/note pages. Pre-v0.41.11 default was false because concepts
    # were treated as link-only stubs; the operational reality is that
    # concept bodies routinely contain definitions, distinctions, and
    # claims that belong in the facts table.
    #
    # Important: this flip is SEMANTIC ONLY for v0.41.11. The post-sync
    # backstop uses hardcoded ELIGIBLE_TYPES in src/core/facts/eligibility.ts
    # which does NOT read pack extractable, so the flip has zero
    # behavioral effect on the backstop today. Power-users who want
    # concept extraction run `gbrain extract-facts --type concept --force`
    # explicitly. The pack-driven-ELIGIBLE_TYPES refactor (which would
    # make this flag actually drive backstop behavior) is a v0.42+ TODO.
    extractable: true
    expert_routing: false

  - name: person
    primitive: entity
    path_prefixes:
      - people/
      - person/
    aliases: []
    extractable: false
    expert_routing: true

  - name: company
    primitive: entity
    path_prefixes:
      - companies/
      - company/
    aliases: []
    extractable: false
    expert_routing: true

  - name: deal
    primitive: temporal
    path_prefixes:
      - deals/
      - deal/
    aliases: []
    extractable: false
    expert_routing: false

  - name: yc
    primitive: entity
    path_prefixes:
      - yc/
    aliases: []
    extractable: false
    expert_routing: false

  - name: civic
    primitive: entity
    path_prefixes:
      - civic/
    aliases: []
    extractable: false
    expert_routing: false

  - name: project
    primitive: concept
    path_prefixes:
      - projects/
      - project/
    aliases: []
    extractable: false
    expert_routing: false

  - name: source
    primitive: media
    path_prefixes:
      - sources/
      - source/
    aliases: []
    extractable: true
    expert_routing: false

  - name: media
    primitive: media
    path_prefixes:
      - media/
    aliases: []
    extractable: false
    expert_routing: false

  # BrainBench v1 amara-life-v1 corpus directories.
  - name: email
    primitive: temporal
    path_prefixes:
      - emails/
      - email/
    aliases: []
    extractable: true
    expert_routing: false

  - name: slack
    primitive: temporal
    path_prefixes:
      - slack/
    aliases: []
    extractable: true
    expert_routing: false

  - name: calendar-event
    primitive: temporal
    path_prefixes:
      - cal/
      - calendar/
    aliases: []
    extractable: true
    expert_routing: false

  - name: note
    primitive: concept
    path_prefixes:
      - notes/
      - note/
    aliases: []
    extractable: true
    expert_routing: false

  - name: meeting
    primitive: temporal
    path_prefixes:
      - meetings/
      - meeting/
    aliases: []
    extractable: true
    expert_routing: false

  # v0.41.11+ — long-running chat/transcript pages. Lives under
  # conversations/. `temporal` primitive (events through time, not an
  # entity surface). `extractable: true` because the batch facts
  # extraction command (gbrain extract-conversation-facts) walks
  # these by type. Promoted from gbrain-recommended into gbrain-base
  # because imported chat history is now a universal pattern, not
  # an operational-brain niche.
  - name: conversation
    primitive: temporal
    path_prefixes:
      - conversations/
    aliases: []
    extractable: true
    expert_routing: false

  # v0.41.11+ — atomic claim units. An `atom` is the smallest
  # extractable unit of knowledge a higher-level page can reference
  # (one quote, one statistic, one milestone). Atoms ARE the
  # extracted form, so `extractable: false` — running the fact
  # extractor on an atom would loop on its own output. The
  # `annotation` primitive is the right home: atoms annotate a
  # source, they do not stand alone as entities.
  - name: atom
    primitive: annotation
    path_prefixes:
      - atoms/
    aliases: []
    extractable: false
    expert_routing: false

  # v0.42.x — Life Chronicle (#2390). `event` = timeline atom
  # (when·where·who·what) backlinking to a depth page; `diary` = timestamped
  # first-person interiority. Both `temporal` (events through time, not entity
  # surfaces). `extractable: false`: events are already the atomic form, and
  # diary interiority is NEVER mined into the facts table (privacy/consent).
  - name: event
    primitive: temporal
    path_prefixes:
      - life/events/
    aliases: []
    extractable: false
    expert_routing: false

  - name: diary
    primitive: temporal
    path_prefixes:
      - life/diary/
    aliases: []
    extractable: false
    expert_routing: false

  # Types with no path prefix (set explicitly via frontmatter).
  - name: code
    primitive: media
    path_prefixes: []
    aliases: []
    extractable: false
    expert_routing: false

  - name: image
    primitive: media
    path_prefixes: []
    aliases: []
    extractable: false
    expert_routing: false

  - name: synthesis
    primitive: annotation
    path_prefixes: []
    aliases: []
    extractable: false
    expert_routing: false

  # Receipt page written by the v0.41.23 extract framework after every
  # extractor run. Demoted in search via the 0.3x source-boost on the
  # `extracts/` prefix (see src/core/search/source-boost.ts). Always
  # carries `dream_generated: true` + `type: extract_receipt` in
  # frontmatter so the eligibility predicate's anti-loop guard can
  # reject it via either check (belt + suspenders per D-EXTRACT-19).
  - name: extract_receipt
    primitive: annotation
    path_prefixes:
      - extracts/
    aliases: []
    extractable: false
    expert_routing: false

# Link verbs — ordered to match inferLinkType priority in link-extraction.ts.
# Each entry carries the regex pattern that triggers the verb. Inferences
# without a pattern (e.g. type-bound: meeting → attended) are encoded via
# the inference.page_type field. ReDoS guard (E9 + T24) enforces the
# 50ms-per-regex / 500ms-per-page budget at runtime.
link_types:
  - name: attended
    inference:
      page_type: meeting

  - name: image_of
    inference:
      page_type: image

  - name: founded
    inference:
      regex: \b(founded|founder of|co-?founded|started)\b

  - name: invested_in
    inference:
      regex: \b(invested in|backed|seeded|funded|wrote a check)\b

  - name: advises
    inference:
      regex: \b(advises|advisor|advising|advisor to)\b

  - name: works_at
    inference:
      regex: \b(works? at|employed by|works? for|joined|hired by|ceo of|cto of|cmo of)\b

  - name: yc_partner

  - name: led_round

  - name: discussed_in

  - name: source

  - name: related_to

  - name: mentions

# Frontmatter field → link verb mapping (FRONTMATTER_LINK_MAP).
# Page-typed: the source page's type determines which verb applies.
# Untyped: applies to any page type (e.g. `sources:` → discussed_in).
frontmatter_links:
  - page_type: person
    fields: [company, companies]
    link_type: works_at

  - page_type: person
    fields: [founded]
    link_type: founded

  - page_type: company
    fields: [key_people]
    link_type: works_at

  - page_type: company
    fields: [partner]
    link_type: yc_partner

  - page_type: company
    fields: [investors]
    link_type: invested_in

  - page_type: deal
    fields: [investors]
    link_type: invested_in

  - page_type: deal
    fields: [lead]
    link_type: led_round

  - page_type: meeting
    fields: [attendees]
    link_type: attended

# Enrichable types (consulted by enrichment-service + completeness rubric).
# Pre-v0.38 hardcoded to person + company + deal; widened here so
# packs can declare their own enrichable types without forking the engine.
enrichable_types:
  - type: person
    rubric: person-default
  - type: company
    rubric: company-default
  - type: deal
    rubric: deal-default

# Filing rules (per-kind directory enforcement). Mirrors
# skills/_brain-filing-rules.json's surface so doctor + check-resolvable
# can audit against pack rules instead of the global JSON.
filing_rules:
  - kind: person
    directory: people/
    examples:
      - people/alice
  - kind: company
    directory: companies/
    examples:
      - companies/acme
  - kind: deal
    directory: deals/
    examples:
      - deals/acme-seed
  - kind: meeting
    directory: meetings/
    examples:
      - meetings/2026-04-03
  - kind: conversation
    directory: conversations/
    examples:
      - conversations/imessage/alice-example
  - kind: atom
    directory: atoms/
    examples:
      - atoms/2026-04-12-revenue-claim
