Taxonomy

FOLIO is organized into 24 top-level branches, each rooted at a specific OWL class and enumerated by the FOLIOTypes enum. The library exposes a get_<branch>() helper for every branch, plus the generic get_parents, get_children, and get_subgraph traversal methods for walking the class hierarchy by any IRI.

This page covers the 24 branch helpers, the depth controls that keep big branches fast, the dict-returning get_folio_branches() convenience, the three traversal primitives (and their gotchas), and the FOLIO_TYPE_IRIS map that lets you reference branch roots directly.

The 24 FOLIO branches

Every top-level branch is an entry in the FOLIOTypes enum, and every branch root’s short IRI lives in the FOLIO_TYPE_IRIS dictionary. Both are importable from folio.graph. The table below lists each branch, its helper method, its full-depth class count against the FOLIO 2.0.0 ontology, and a one-line description of what it covers.

FOLIOTypes memberHelper methodClass countWhat it covers
ACTOR_PLAYERget_player_actors()563Roles played by humans, organizations, or systems in legal matters
AREA_OF_LAWget_areas_of_law()174Substantive areas of legal practice
ASSET_TYPEget_asset_types()345Property and asset categories
COMMUNICATION_MODALITYget_communication_modalities()11Channels through which legal communication happens
CURRENCYget_currencies()178National and supranational currencies
DATA_FORMATget_data_formats()17File and data formats (HTML, JSON, RTF, etc.)
DOCUMENT_ARTIFACTget_document_artifacts()2,796Document and artifact types
ENGAGEMENT_TERMSget_engagement_terms()343Terms governing legal engagements
EVENTget_events()401Legal events (meetings, depositions, hearings)
FORUMS_VENUESget_forum_venues()2,180Courts, tribunals, and other adjudicative venues
GOVERNMENTAL_BODYget_governmental_bodies()1,585Government agencies and bodies
INDUSTRYget_industries()2,137Industry categories
LANGUAGEget_languages()489Human languages
FOLIO_TYPEget_folio_types()3Meta-types (Instance, FOLIO Template, Query)
LEGAL_AUTHORITIESget_legal_authorities()82Sources of law (constitutions, statutes, regulations)
LEGAL_ENTITYget_legal_entities()517Legal-entity forms (corporations, partnerships, etc.)
LOCATIONget_locations()3,782Geographic locations (countries, regions, cities)
MATTER_NARRATIVEget_matter_narratives()13Matter narrative types
MATTER_NARRATIVE_FORMATget_matter_narrative_formats()2Narrative formats (HTML, TXT)
OBJECTIVESget_objectives()5,409Legal and business objectives
SERVICEget_services()434Legal services and practice areas
STANDARDS_COMPATIBILITYget_standards_compatibilities()868Standards and compliance frameworks
STATUSget_statuses()23Status values for engagements and services
SYSTEM_IDENTIFIERSget_system_identifiers()13System identifier types

Two spelling notes worth burning in: the Actor / Player helper is get_player_actors() (not get_actors), and the Forums and Venues helper is get_forum_venues() (not get_forums_and_venues). Calling the wrong name raises AttributeError — the rest of the helpers match their branch names in the obvious way.

The counts above are at full depth — every descendant reachable from the branch root. If you want only the immediate children of a root (the top-level categories within a branch), pass max_depth=1. All 24 helpers share the same signature:

get_<branch>(max_depth: int = DEFAULT_MAX_DEPTH) -> List[OWLClass]

where DEFAULT_MAX_DEPTH = 16 (imported from folio.graph). 16 is deep enough to reach every leaf in the current ontology without risking runaway recursion on a malformed import. You can always pass a smaller value for speed, or an explicit larger value if you ever graft a deeper taxonomy onto FOLIO.

Calling a branch helper

Each helper returns a flat list of OWLClass objects. Order is traversal order from the branch root, not sorted, so don’t rely on alphabetization.

Areas of Law

from folio import FOLIO

f = FOLIO()

areas = f.get_areas_of_law()
print(len(areas))
for c in areas[:3]:
    print(repr(c.label))

# Output:
# 174
# 'Constitutional and Civil Rights Law'
# 'Individual Rights Law'
# 'Environmental, Social, and Governance Law'

174 classes total — small enough to enumerate in full for most applications, including fanning out into an LLM prompt or populating a dropdown.

Locations

locations = f.get_locations()
print(len(locations))
for c in locations[:3]:
    print(repr(c.label))

# Output:
# 3782
# 'Europe'
# 'Slovenia'
# 'Horjul'

3,782 classes — the Location branch goes all the way down to municipalities, so the first few labels hitch a ride through Europe before the traversal unwinds. If you only need continents, countries, and U.S. states, use max_depth to cut the tree short.

Document types

docs = f.get_document_artifacts()
print(len(docs))
for c in docs[:3]:
    print(repr(c.label))

# Output:
# 2796
# 'Document Provenance'
# 'Document Types'
# 'Legal Assistance Document'

2,796 classes covering every document and artifact type FOLIO models — contracts, pleadings, opinions, forms, evidence exhibits, and so on.

Limiting depth with max_depth

Branch helpers fan out recursively to DEFAULT_MAX_DEPTH = 16. For a small branch like Areas of Law, that’s fine. For Locations, Industries, or Objectives — the multi-thousand-class branches — it can be noticeably slow if you only need the top-level categories.

Pass an explicit max_depth to stop early:

top_level = f.get_areas_of_law(max_depth=1)
print(len(top_level))  # only direct children of the Area of Law root

full_tree = f.get_areas_of_law()
print(len(full_tree))

# Output:
# 31
# 174

Limit depth whenever you only need top-level categories, whenever you’re enumerating a branch just to show a hierarchy drill-down one level at a time, or whenever you’re pre-computing a facet dashboard over Locations / Industries / Objectives. For everything else, the full-depth default is fine — 16 covers every branch in the current ontology.

max_depth=0 is a special case: it short-circuits the recursion and returns an empty list (no descendants enumerated). That’s rarely what you want from a branch helper, but it’s handy as a sanity check. max_depth=1 is the most common manual value — it gives you exactly the direct children of the branch root.

All branches at once: get_folio_branches()

get_folio_branches() calls every branch helper for you and returns a Dict[FOLIOTypes, List[OWLClass]] keyed by the enum member — 24 keys, one per branch. (The docstring in the source still says List[OWLClass]; it’s a dict.) Useful for fanning out searches, building dashboards, or writing tooling that needs to reason over every branch at once.

branches = f.get_folio_branches(max_depth=1)
print(type(branches).__name__, len(branches))
for type_, classes in branches.items():
    print(f"{type_.value}: {len(classes)}")

# Output:
# dict 24
# Actor / Player: 6
# Area of Law: 31
# Asset Type: 4
# Communication Modality: 3
# Currency: 178
# Data Format: 17
# Document / Artifact: 7
# Engagement Terms: 14
# Event: 14
# Forums and Venues: 3
# Governmental Body: 10
# Industry: 21
# Language: 487
# FOLIO Type: 3
# Legal Authorities: 14
# Legal Entity: 6
# Location: 8
# Matter Narrative: 8
# Matter Narrative Format: 2
# Objectives: 13
# Service: 5
# Standards Compatibility: 5
# Status: 3
# System Identifiers: 4

Because the keys are FOLIOTypes enum members, type_.value gives you the human label ("Area of Law") and type_.name gives you the Python identifier ("AREA_OF_LAW").

A common idiom is to build a flat lookup from short IRI to branch label, so you can annotate search results with their branch of origin:

branches = f.get_folio_branches()  # full depth
iri_to_branch = {
    c.iri.rsplit("/", 1)[-1]: type_.value
    for type_, classes in branches.items()
    for c in classes
}
print(iri_to_branch["R8BD30978Ccbc4C2f0f8459f"])

# Output:
# Location

Run once at startup, reuse everywhere.

Traversing the taxonomy

The branch helpers are thin wrappers around three generic traversal methods. If you know a specific IRI and want to walk around it — for example, to render a breadcrumb trail, enumerate everything under a single area of law, or gather a self-contained subtree for an LLM prompt — call these directly.

get_parents(iri, max_depth=16)

Walks up the sub_class_of edges and returns the chain of ancestor classes. Two things to watch for:

  • The list includes the starting class itself as element 0.
  • The list ends with a synthetic OWLClass(label=None, iri="http://www.w3.org/2002/07/owl#Thing") sentinel representing the OWL root. Any renderer that expects label to be a string must guard against None.
parents = f.get_parents("R8BD30978Ccbc4C2f0f8459f")  # Michigan
print(len(parents))
for p in parents:
    print(f"{p.label!r}  ->  {p.iri}")

# Output:
# 5
# 'Michigan'  ->  https://folio.openlegalstandard.org/R8BD30978Ccbc4C2f0f8459f
# 'United States of America (Location)'  ->  https://folio.openlegalstandard.org/R1E70ce4D699e90144cB32b8
# 'North America'  ->  https://folio.openlegalstandard.org/RE001ab376fa25C94f1244be
# 'Location'  ->  https://folio.openlegalstandard.org/R9aSzp9cEiBCzObnP92jYFX
# None  ->  http://www.w3.org/2002/07/owl#Thing

Five elements: Michigan, its country, its continent, the Location branch root, and owl:Thing. If you want just the “real” ancestors, slice to parents[1:-1] or filter out label is None:

ancestors = [p for p in f.get_parents(iri) if p.label is not None and p.iri != iri]

Because get_parents follows every sub_class_of edge, a class with multiple parents produces a wider-than-linear chain — the traversal recurses into each parent in turn, so you may see the same ancestor more than once when two branches converge higher up the tree.

get_children(iri, max_depth=16)

Walks down the parent_class_of edges and returns descendant classes. Unlike get_parents, it excludes the starting class. Unlike a proper set traversal, it can contain duplicates when the same class is reachable via multiple inheritance paths.

children = f.get_children("RCIPwpgRpMs1eVz4vPid0pV")  # Contract Law
print(len(children))
for c in children:
    print(repr(c.label))

# Output:
# 7
# 'Property Rights and Transactions Law'
# 'Civil Contract Law'
# 'Property Rights and Transactions Law'
# 'Commercial Transactions Law'
# 'Government Contracts Law'
# 'Employment Contracts Law'
# 'Independent Contractor Law'

Note that Property Rights and Transactions Law appears twice — it’s a child of Contract Law through two different paths (a common pattern in FOLIO wherever one class legitimately falls under multiple parents). The duplicate is not a bug in the traversal; it’s a faithful enumeration of the graph. If you need unique results, dedupe by IRI:

seen = set()
unique = [c for c in children if not (c.iri in seen or seen.add(c.iri))]
print(len(unique))  # 6

Calling get_children on a leaf class returns []:

print(f.get_children("R8BD30978Ccbc4C2f0f8459f"))  # Michigan (leaf)

# Output:
# []

get_subgraph(iri, max_depth=16)

Same as get_children, but includes the starting class as element 0. Use this when you want “everything under this branch including the root itself” — for example, when exporting a self-contained subtree to JSON or Markdown.

sub = f.get_subgraph("RCIPwpgRpMs1eVz4vPid0pV", max_depth=2)  # Contract Law, 2 deep
print(len(sub))
for c in sub:
    print(repr(c.label))

# Output:
# 8
# 'Contract Law'
# 'Property Rights and Transactions Law'
# 'Civil Contract Law'
# 'Property Rights and Transactions Law'
# 'Commercial Transactions Law'
# 'Government Contracts Law'
# 'Employment Contracts Law'
# 'Independent Contractor Law'

Eight classes: Contract Law itself plus its seven descendants (including the same duplicate). Under the hood, every branch helper is self.get_children(FOLIO_TYPE_IRIS[<branch>], max_depth=...) — so whenever you need “the branch root plus everything below it,” reach for get_subgraph on the corresponding type IRI instead of the branch helper.

To summarize the three in one line: get_parents goes UP from an IRI (and includes self + an owl:Thing sentinel); get_children goes DOWN excluding self (may contain duplicates); get_subgraph goes DOWN including self (also may contain duplicates). All three accept a max_depth argument, all three return List[OWLClass], and all three accept short IRIs, full URIs, or legacy soli: / lmss.sali.org URLs interchangeably.

Branch IRI lookups

FOLIO_TYPE_IRIS is the canonical mapping from FOLIOTypes enum members to their root-class short IRIs. Import it directly when you need a branch root without calling a helper — for example, to pass as the parent_iri of a structured query.

from folio.graph import FOLIOTypes, FOLIO_TYPE_IRIS

area_of_law_iri = FOLIO_TYPE_IRIS[FOLIOTypes.AREA_OF_LAW]
print(area_of_law_iri)

# Use it as a query parent:
leaves = f.query(parent_iri=area_of_law_iri, has_children=False, limit=5)
for c in leaves:
    print(repr(c.label))

# Output:
# RSYBzf149Mi5KE0YtmpUmr
# 'Patent Law'
# 'Reduction in Force Law'
# 'Trade Secret Law'
# 'Cybersecurity Law'
# "Indigenous People's Law"

One thing to watch: the values in FOLIO_TYPE_IRIS are short IDs, not full URIs. If you need the full IRI form, prefix with https://folio.openlegalstandard.org/. All of the FOLIO client’s class-lookup and traversal methods accept either form — f[short_id], f[full_iri], and f.get_parents(short_id) all work — so you generally don’t need to expand the string yourself.

Reach for FOLIO_TYPE_IRIS directly (instead of calling a get_* helper) when you want the root class itself rather than its descendants — for example, to fetch metadata like the root’s definition, to use it as a parent_iri filter in query(), or to include it as the starting node in get_subgraph(). The branch helpers always start one level below the root, so they don’t return the root class.

See also

See also: Querying for filter-based access to taxonomy slices (including parent_iri and has_children), Properties & Relationships for object properties and the triples API, and API Reference for the complete method catalog.