For the complete documentation index, see llms.txt. This page is also available as Markdown.

Reading a complete layer

A complete, annotated .lynk/ project for Grove (B2B SaaS) — every file of a small correct layer, end to end, with the reasoning behind each choice. Read when you want the whole shape at once instead o

What a small, correct .lynk/ project looks like end to end — every file of Grove's layer, and why each choice was made.

When you need this

The concept pages each explain one file type in isolation. This page shows them fitting together: one project, one domain, two entities, a skill, and a policy — small enough to read in one sitting, complete enough that every cross-reference resolves. Read it when you're building your first layer or reviewing someone else's.

The layer at a glance

Two entities carry Grove's model — customer (the account) and subscription (the billing object) — in a single core domain.

.lynk/
├── lynk.yml
├── LYNK.md
├── GLOSSARY.yml
└── domains/
    └── core/
        ├── entities/
        │   ├── customer/
        │   │   ├── ENTITY.md
        │   │   └── schema.yml
        │   └── subscription/
        │       ├── ENTITY.md
        │       └── schema.yml
        ├── skills/
        │   └── churn-investigation/
        │       └── SKILL.md
        └── policies/
            └── output-format/
                └── POLICY.md

File by file

lynk.yml

No topology block: with one domain there is nothing to compose across, and the default (medallion, no shared domain) already says "each domain references only itself and the root files." Adding shared_domain: core becomes worthwhile only when a second domain appears. See lynk.yml.

LYNK.md

Orientation only — facts no single entity owns. Notice what is not here: the test-account exclusion is a rule about customer rows, so it lives on that entity's ENTITY.md, not in orientation. See LYNK.md.

GLOSSARY.yml

Vocabulary only — each entry is key → name / description, no formulas, no pointers to entities. The keys are stable @ addresses: the skill below injects @glossary.logo_churn.description. See GLOSSARY.yml.

domains/core/entities/customer/ENTITY.md

The description states the grain and what the entity is for — that line is what the agent reads at index time to decide whether to load the entity. The body carries only what every analysis of this entity needs. See ENTITY.md.

domains/core/entities/customer/schema.yml

Three feature shapes in one file: direct column reads, a derived sql expression (customer_tier), and a cross-entity aggregate (total_mrr) — which is a feature, not a metric, because the rows it aggregates belong to subscription. Every feature has exactly the fields name / description / sql / data_type, plus join_name only where the expression crosses the relationship. The relationship step joins on customer.id and subscription.customer_id, so both are declared features on their entities. See schema.yml.

domains/core/entities/subscription/ENTITY.md

Frontmatter only — this entity has no quirks worth a body, and the body is optional. The description alone makes it loadable.

domains/core/entities/subscription/schema.yml

customer_id is declared because a relationship step joins on it; the key subscription_id is not declared, because nothing references it — keys are not features, and only touched columns earn a declaration. total_mrr lives here, on the entity whose rows it sums; customer exposes it across the boundary as a feature. The relationship is customer_to_subscription seen from the other side: its own name, its own many_to_one cardinality, its own sql. See relationships.

domains/core/skills/churn-investigation/SKILL.md

A skill uses the schema, it never defines it — every @ reference here resolves to a feature or glossary entry that already exists, and no value is computed inside the prose. The description is what the agent reads to decide whether to load the skill. See Skill.

domains/core/policies/output-format/POLICY.md

The folder is named after the Lynk policy type output-format, so this file fully replaces Lynk's shipped default. It carries operating behavior, not data facts or reasoning procedures. See Policy.

What to notice

  • Keys are not features — touched columns are. customer.id and subscription.customer_id are declared because a relationship step joins on them; subscription_id is not, because nothing references it. Relationships

  • Metrics are entity-local and take no arguments. total_mrr is defined once, on subscription; customer reaches it as a feature whose sql wraps metric() with a join_name. Metric

  • Feature fields are exactly six. name / description / sql / data_type, plus optional join_name and filter — no types, no templating. And every description states what the value is (grain, units, enums), because the agent reasons from it. Feature

  • Each rule has one home. The test-account exclusion lives on customer's ENTITY.md; LYNK.md carries only what no entity owns. ENTITY.md · LYNK.md

  • The glossary is vocabulary, not computation. key → name / description only; anything formula-shaped belongs in schema or a skill. GLOSSARY.yml

  • Names match folders, everywhere. customer, churn-investigation, output-format — frontmatter name equals folder name, and the domain is the folder under domains/. Layout and naming

Last updated