# page_core URL: /api/core/page/page_core/ Section: page -------------------------------------------------------------------------------- page_core - Bengal window.BENGAL_THEME_DEFAULTS = { appearance: 'dark', palette: 'snow-lynx' }; // Progressive Enhancement System Configuration window.Bengal = window.Bengal || {}; window.Bengal.enhanceBaseUrl = '/bengal/assets/js/enhancements'; window.Bengal.watchDom = true; window.Bengal.debug = false; (function () { try { var defaults = window.BENGAL_THEME_DEFAULTS || { appearance: 'system', palette: '' }; var defaultAppearance = defaults.appearance; if (defaultAppearance === 'system') { defaultAppearance = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) ? 'dark' : 'light'; } var storedTheme = localStorage.getItem('bengal-theme'); var storedPalette = localStorage.getItem('bengal-palette'); var theme = storedTheme ? (storedTheme === 'system' ? defaultAppearance : storedTheme) : defaultAppearance; var palette = storedPalette ?? defaults.palette; document.documentElement.setAttribute('data-theme', theme); if (palette) { document.documentElement.setAttribute('data-palette', palette); } } catch (e) { document.documentElement.setAttribute('data-theme', 'light'); } })(); Skip to main content Magnifying Glass ESC Recent Clear Magnifying Glass No results for "" Try different keywords or check your spelling Start typing to search... ↑↓ Navigate ↵ Open ESC Close Powered by Lunr ᓚᘏᗢ Documentation Info About Arrow Clockwise Get Started Note Tutorials File Text Content Palette Theming Settings Building Starburst Extending Bookmark Reference Learning Tracks Releases Dev GitHub API Reference bengal CLI Magnifying Glass Search ⌘K Palette Appearance Chevron Down Mode Monitor System Sun Light Moon Dark Palette Snow Lynx Brown Bengal Silver Bengal Charcoal Bengal Blue Bengal List ᓚᘏᗢ Magnifying Glass Search X Close Documentation Info About Arrow Clockwise Get Started Note Tutorials File Text Content Palette Theming Settings Building Starburst Extending Bookmark Reference Learning Tracks Releases Dev GitHub API Reference bengal CLI Palette Appearance Chevron Down Mode Monitor System Sun Light Moon Dark Palette Snow Lynx Brown Bengal Silver Bengal Charcoal Bengal Blue Bengal API Reference __main__ bengal Caret Right Folder Analysis community_detection graph_analysis graph_reporting graph_visualizer knowledge_graph link_suggestions link_types page_rank path_analysis performance_advisor results Caret Right Folder Assets manifest pipeline Caret Right Folder Autodoc base config docstring_parser utils virtual_orchestrator Caret Right Folder Extractors cli openapi python Caret Right Folder Models cli common openapi python Caret Right Folder Cache asset_dependency_map cache_store cacheable compression dependency_tracker page_discovery_cache query_index query_index_registry taxonomy_index utils Caret Right Folder Build Cache autodoc_tracking core file_tracking fingerprint parsed_content_cache rendered_output_cache taxonomy_index_mixin validation_cache Caret Right Folder Indexes author_index category_index date_range_index section_index Caret Right Folder Cli __main__ base site_templates utils Caret Right Folder Commands assets build clean collections config debug explain fix health init perf project serve site skeleton sources theme utils validate Caret Right Folder Graph __main__ bridges communities orphans pagerank report suggest Caret Right Folder New config presets scaffolds site wizard Caret Right Folder Helpers cli_app_loader cli_output config_validation error_handling menu_config metadata progress site_loader traceback validation Caret Right Folder Skeleton hydrator schema Caret Right Folder Templates base registry Caret Right Folder Blog template Caret Right Folder Changelog template Caret Right Folder Default template Caret Right Folder Docs template Caret Right Folder Landing template Caret Right Folder Portfolio template Caret Right Folder Resume template Caret Right Folder Collections errors loader schemas validator Caret Right Folder Config defaults deprecation directory_loader env_overrides environment feature_mappings hash loader merge origin_tracker validators Caret Right Folder Content Layer entry loaders manager source Caret Right Folder Sources github local notion rest Caret Right Folder Content Types base registry strategies Caret Right Folder Core build_context cascade_engine menu section theme Caret Right Folder Asset asset_core css_transforms Caret Right Folder Page computed content metadata navigation operations page_core proxy relationships utils Caret Right Folder Site core data discovery factories page_caches properties section_registry theme Caret Right Folder Debug base config_inspector content_migrator delta_analyzer dependency_visualizer explainer incremental_debugger models reporter shortcode_sandbox Caret Right Folder Discovery asset_discovery content_discovery Caret Right Folder Fonts downloader generator Caret Right Folder Health autofix base health_check report Caret Right Folder Linkcheck async_checker ignore_policy internal_checker models orchestrator Caret Right Folder Validators anchors assets cache config connectivity cross_ref fonts links menu navigation output performance rendering rss sitemap taxonomy tracks Caret Right Folder Directives analysis checkers constants Caret Right Folder Orchestration asset content full_to_incremental incremental menu postprocess related_posts render section static streaming taxonomy Caret Right Folder Postprocess html_output redirects rss sitemap special_pages Caret Right Folder Output Formats index_generator json_generator llm_generator lunr_index_generator txt_generator utils Caret Right Folder Rendering api_doc_enhancer asset_extractor errors jinja_utils link_transformer link_validator pygments_cache renderer template_context template_profiler validator Caret Right Folder Parsers base factory mistune native_html pygments_patch python_markdown Caret Right Folder Pipeline core output thread_local toc transforms Caret Right Folder Plugins badges cross_references inline_icon term variable_substitution Caret Right Folder Directives _icons admonitions badge base button cache cards checklist code_tabs container contracts data_table dropdown embed errors example_label fenced figure glossary icon include list_table literalinclude marimo navigation options rubric steps tabs target term terminal tokens utils validator video Caret Right Folder Template Engine asset_url core environment manifest menu url_helpers Caret Right Folder Template Functions advanced_collections advanced_strings autodoc collections content crossref data dates debug files get_page i18n icons images math_functions navigation pagination_helpers seo strings tables taxonomies theme urls Caret Right Folder Server build_handler component_preview constants dev_server live_reload pid_manager reload_controller request_handler request_logger resource_manager utils Caret Right Folder Services validation Caret Right Folder Themes config Caret Right Folder Utils atomic_write autodoc build_context build_stats build_summary cli_output css_minifier dates dotdict error_handlers file_io file_lock hashing incremental_constants js_bundler live_progress logger metadata observability page_initializer pagination path_resolver paths performance_collector performance_report profile progress retry rich_console sections swizzle text theme_registry theme_resolution thread_local traceback_config traceback_renderer url_normalization url_strategy Core Page ᗢ Caret Down Link Copy URL External Open LLM text Copy Copy LLM text Share with AI Ask Claude Ask ChatGPT Ask Gemini Ask Copilot Module core.page.page_core PageCore - Cacheable page metadata shared between Page, PageMetadata, and PageProxy. This module defines PageCore, the single source of truth for all cacheable page metadata. Any field added to PageCore automatically becomes available in: Page: via page.core.field or @property delegate (e.g., page.title) PageMetadata: IS PageCore (type alias in cache/page_discovery_cache.py) PageProxy: via proxy.field property (no lazy load needed for core fields) This design prevents cache bugs by making it impossible to have mismatched field definitions between Page, PageMetadata, and PageProxy. The compiler enforces that all three representations stay in sync. Architecture: PageCore = Cacheable fields only (title, date, tags, etc.) Page = PageCore + non-cacheable fields (content, rendered_html, toc, etc.) PageMetadata = PageCore (type alias for caching) PageProxy = Wraps PageCore (lazy loads only non-core fields) What Goes in PageCore? ✅ DO include if: Field comes from frontmatter (title, date, tags, slug, etc.) Field is computed without full content parsing (url path components) Field needs to be accessible in templates without lazy loading Field is cascaded from section _index.md (type, layout, etc.) Field is used for navigation (section reference as path) ❌ DO NOT include if: Field requires full content parsing (toc, excerpt, meta_description) Field is a build artifact (output_path, links, rendered_html) Field changes every build (timestamp, render_time) Field is computed from other non-cacheable fields Example Usage: # Creating a PageCore from datetime import datetime core = PageCore( source_path="content/posts/my-post.md", # String path for JSON compatibility title="My Post", date=datetime(2025, 10, 26), tags=["python", "web"], slug="my-post", type="doc", ) # Using in Page (composition) from bengal.core.page import Page page = Page( core=core, content="# Hello World", rendered_html="<h1>Hello World</h1>", ) # Accessing fields via property delegates assert page.title == "My Post" # Property delegate assert page.core.title == "My Post" # Direct access # Caching (PageMetadata = PageCore) from dataclasses import asdict import json metadata = page.core # Already PageCore! json_str = json.dumps(asdict(metadata), default=str) # Loading from cache from bengal.core.page.proxy import PageProxy loaded_core = PageCore(**json.loads(json_str)) proxy = PageProxy(core=loaded_core, loader=load_page_fn) # Accessing cached fields (no lazy load) assert proxy.title == "My Post" # Direct from core Adding New Fields: When adding a new cacheable field: 1. Add to PageCore (this file): @dataclass class PageCore: # ... existing fields ... author: str | None = None # NEW 2. Add @property delegate to Page (bengal/core/page/__init__.py): @property def author(self) -> str | None: return self.core.author 3. Add @property delegate to PageProxy (bengal/core/page/proxy.py): @property def author(self) -> str | None: return self._core.author That's it! Field is now available in Page, PageMetadata, and PageProxy. The compiler will catch any missing implementations. See Also: architecture/object-model.md - PageProxy & Cache Contract section plan/active/rfc-cache-proxy-contract.md - Design rationale CONTRIBUTING.md - Guidelines for adding fields View source 1 Class Classes PageCore dataclass Cacheable page metadata shared between Page, PageMetadata, and PageProxy. This is the single sourc… 3 Caret Right Cacheable page metadata shared between Page, PageMetadata, and PageProxy. This is the single source of truth for all cacheable page data. All fields here can be serialized to JSON and stored in .bengal/page_metadata.json for incremental builds. Inherits from Cacheable Attributes Name Type Description source_path str Path to source markdown file (relative to content dir). Used as cache key and for file change detection. title str Page title from frontmatter or filename. Required field, defaults to "Untitled" if not provided. date datetime | None Publication date from frontmatter. Used for sorting, archives, and RSS feeds. None if not specified. tags list[str] List of tag strings from frontmatter. Used for taxonomy pages and filtering. Empty list if not specified. slug str | None URL slug for this page. Overrides default slug derived from filename. None means use default. weight int | None Sort weight within section. Lower numbers appear first. None means use default sorting. lang str | None Language code for i18n (e.g., "en", "es", "fr"). None means use site default language. type str | None Page type from frontmatter or cascaded from section. Determines which layout/template to use (e.g., "doc", "post", "page"). Cascaded from section _index.md if not specified in page frontmatter. variant str | None description str | None props dict[str, Any] section str | None Section path (e.g., "content/docs" or "docs"). Stored as path string, not Section object, for stability across rebuilds. None for root-level pages. file_hash str | None SHA256 hash of source file content. Used for cache validation to detect file changes. None during initial creation, populated during caching. Design Notes: - All fields are JSON-serializable (no object references) - Paths stored as strings (resolved to objects via registry on access) - Optional fields default to None (not all pages have all metadata) - No circular references (enables straightforward serialization) - No computed fields that require full content (those go in Page) Why Strings Instead of Path Objects? 1. JSON Serialization: Path objects cannot be directly JSON-serialized. Using strings allows cache files to be saved/loaded without custom handlers. 2. Cache Portability: String paths work across systems without Path object compatibility concerns (Windows vs Unix path separators handled by Path when converting back). 3. Type Consistency: PageMetadata IS PageCore (type alias). Cache expects strings, so PageCore must use strings for type compatibility. 4. Performance: String comparison for cache lookups is marginally faster than Path comparison (matters for incremental builds with 1000+ pages). Convert at boundaries: - Input: Path → str when creating PageCore (Page.post_init) - Output: str → Path when using paths (PageProxy, lookups) Cache Lifecycle: 1. Page created with PageCore during discovery 2. PageCore serialized to JSON and saved to cache 3. On incremental rebuild, PageCore loaded from cache 4. PageProxy wraps PageCore for lazy loading 5. Templates access fields via proxy properties (no load) 6. Full page loaded only if non-core field accessed aliases list[str] Performance — PageCore is ~500 bytes per page (10 fields × ~50 bytes each) - 10,000 pages = ~5MB for all cores (acceptable) - Serialization/deserialization via asdict() is ~10µs per page - Memory overhead negligible vs full Page objects Methods 2 to_cache_dict Serialize PageCore to cache-friendly dictionary. Implements the Cacheable prot… 0 dict[str, Any] Caret Right def to_cache_dict(self) -> dict[str, Any] Serialize PageCore to cache-friendly dictionary. Implements the Cacheable protocol for type-safe caching. Returns dict[str, Any] — Dictionary with all PageCore fields, suitable for JSON serialization. datetime fields are serialized as ISO-8601 strings. from_cache_dict classmethod Deserialize PageCore from cache dictionary. Implements the Cacheable protocol … 1 PageCore Caret Right def from_cache_dict(cls, data: dict[str, Any]) -> PageCore Deserialize PageCore from cache dictionary. Implements the Cacheable protocol for type-safe caching. Parameters 1 data dict[str, Any] Dictionary from cache (JSON-deserialized) Returns PageCore — Reconstructed PageCore instance Internal Methods 1 Caret Right __post_init__ Validate and normalize fields after initialization. This runs automatically af… 0 None Caret Right def __post_init__(self) -> None Validate and normalize fields after initialization. This runs automatically after dataclass initialization. ← Previous page Next → proxy List © 2025 Bengal ᓚᘏᗢ window.BENGAL_LAZY_ASSETS = { tabulator: '/bengal/assets/js/tabulator.min.js', dataTable: '/bengal/assets/js/data-table.js', mermaidToolbar: '/bengal/assets/js/mermaid-toolbar.9de5abba.js', mermaidTheme: '/bengal/assets/js/mermaid-theme.344822c5.js', graphMinimap: '/bengal/assets/js/graph-minimap.cc7e42e3.js', graphContextual: '/bengal/assets/js/graph-contextual.440e59c6.js' }; window.BENGAL_ICONS = { close: '/bengal/assets/icons/close.911d4fe1.svg', enlarge: '/bengal/assets/icons/enlarge.652035e5.svg', copy: '/bengal/assets/icons/copy.3d56e945.svg', 'download-svg': '/bengal/assets/icons/download.04f07e1b.svg', 'download-png': '/bengal/assets/icons/image.c34dfd40.svg', 'zoom-in': '/bengal/assets/icons/zoom-in.237b4a83.svg', 'zoom-out': '/bengal/assets/icons/zoom-out.38857c77.svg', reset: '/bengal/assets/icons/reset.d26dba29.svg' }; Arrow Up X -------------------------------------------------------------------------------- Metadata: - Author: lbliii - Word Count: 2039 - Reading Time: 10 minutes