org-transclusion-blocks enables transclusion into any Org block (src, quote,
example, export, etc.) using header arguments, similar to how Babel uses headers
for code execution (:session, :results, :var). Content fetched via
org-transclusion persists in the buffer file, similarly to using
org-transclusion-detach
- Core Capability: Headers for Transclusion
- Advanced Capability: Component-Based Links
- Features
- Installation
- Quick Start
- Why Header-Based Transclusion?
- Default Headers (No Configuration Required)
- Block Types
- Component-Based Links (Advanced)
- Commands
- Configuration
- Integration with org-transclusion
- Package Ecosystem
- Troubleshooting
- Comparison with Alternatives
- Resources
- Acknowledgments
- License
org-transclusion uses #+transclude: keywords. This package uses block headers:
Before (org-transclusion):
#+transclude: [[file:org-transclusion-blocks.el]] :src elisp :lines 869-949
After (org-transclusion-blocks):
#+HEADER: :transclude [[file:org-transclusion-blocks.el]]
#+HEADER: :transclude-keywords ":lines 869-949"
#+begin_src elisp
#+end_src
The header approach enables:
- Property inheritance: Set
:transcludeonce in property drawer, inherit in all subtree blocks - Babel integration: Combine transclusion with
:session,:results,:exportsin src blocks - Persistent content: Transcluded text remains in buffer file as if detached.
- Block type flexibility: Use quote, example, export, or custom special blocks
- Org syntax escaping: Automatic escaping prevents markup in transcluded Org content from breaking src blocks
For complex links or when validation is desired, decompose into semantic components.
Org’s built-in file: link type supports search options (::*Heading, ::#custom-id).
Decompose into components with validation:
(org-transclusion-blocks-register-type
;; transclusion-type
'file-with-search
;; components
'(:path (:header :file-path
:required t
:validator ,(org-transclusion-blocks-compose-validators
(org-transclusion-blocks-make-non-empty-validator "file path")
(org-transclusion-blocks-make-predicate-validator
#'file-exists-p "file path")))
:search (:header :file-search))
;;constructor
(lambda (components)
(let ((path (plist-get components :path))
(search (plist-get components :search)))
(if search
(format "file:%s::%s" path search)
(format "file:%s" path)))))This registration:
- Uses
org-transclusion-blocks-compose-validatorsto chain two validators make-non-empty-validatorcatches empty pathsmake-predicate-validatorchecks file existence viafile-exists-p- Constructor formats standard
file:PATH::SEARCHlink
Usage:
#+HEADER: :transclude-type file-with-search
#+HEADER: :file-path ~/documents/notes.org
#+HEADER: :file-search *Research
#+begin_src org
#+end_src
Validation catches errors early:
Header :file-path: invalid file path: "~/nonexistent.org"
Without validation, the error occurs during fetch with less helpful message: “Failed to fetch transclusion content”.
Extend the file example with shadowing relationship:
(org-transclusion-blocks-register-type
;;transclusion-type
'file-with-search
;; components
'(:path (:header :file-path
:required t
;; defining validators
:validator ,(org-transclusion-blocks-compose-validators
(org-transclusion-blocks-make-non-empty-validator "file path")
(org-transclusion-blocks-make-predicate-validator
#'file-exists-p "file path")))
:search (:header :file-search
;; defining header incompatibility between :lines and :thing-at-point
:shadowed-by (:transclude-lines :transclude-thing))) ;;defining
;; constructor
(lambda (components)
(let ((path (plist-get components :path))
(search (plist-get components :search)))
(if search
(format "file:%s::%s" path search)
(format "file:%s" path)))))Now using both :file-search and :transclude-lines produces warning:
#+HEADER: :transclude-type file-with-search
#+HEADER: :file-path ~/notes.org
#+HEADER: :file-search *Heading
#+HEADER: :transclude-lines 10-20
Warning:
Header :transclude-lines shadows :file-search; latter will be ignored
The :shadowed-by declaration makes the relationship explicit. User discovers
why their search doesn’t work before debugging.
- custom validators and constructors: already possible but figuring out how to explain clearly. you can look at the raw code for it in HERE
- Direct header transclusion: Use
:transcludeheader in any block without configuration - Property inheritance: Set headers in property drawer, inherit in subtree blocks
- Persistent content: Transcluded text saved to file, works with version control and offline
- Block type support: Works with src, quote, example, export, verse, center, comment, and custom special blocks
- Org syntax escaping: Automatic escaping for Org sources prevents headline/keyword collisions in src blocks
- Component decomposition: Break complex links into validated semantic headers (requires registration)
- Pre-validation: Catch errors before content fetch with component-specific messages
- Interaction constraints: Declare required components, shadowing, dependencies, conflicts
- Validator composition: Utilities for common patterns (non-empty, regexp, predicate)
- Babel integration: Full compatibility with
:session,:results,:var,:exportsin src blocks - Introspection: Commands to discover types, inspect configurations, validate without fetching
(add-to-list 'load-path "/path/to/org-transclusion-blocks")
(require 'org-transclusion-blocks)Add :transclude header to any block:
#+HEADER: :transclude [[file:~/documents/notes.org::*Research]]
Run M-x org-transclusion-blocks-add. Content from target appears in block body:
#+HEADER: :transclude [[file:~/documents/notes.org::*Research]]
#+begin_src org
* Research
Prior work in this area shows...
#+end_src
Content persists in file. Version control sees it. Works offline.
Use :transclude-keywords to pass org-transclusion options:
#+HEADER: :transclude [[file:~/notes.org::*Heading]]
#+HEADER: :transclude-keywords ":only-contents :lines 1-10"
#+begin_src org
#+end_src
This passes :only-contents :lines 1-10 to org-transclusion.
Warning
Some org-transclusion keywords don’t work as intented at the moment (:level, :exclude-elements).
Set :transclude once, inherit in subtree:
* Research Notes
:PROPERTIES:
:header-args: :transclude [[file:~/research.org]]
:END:
** Introduction Section
#+HEADER: :transclude-keywords ":only-contents :lines 1-5"
#+begin_src org
#+end_src
* Literature Review Section
#+HEADER: :transclude-keywords ":only-contents :lines 10-15"
#+begin_src org
#+end_src
Both blocks inherit :transclude from property drawer. Each adds
:transclude-keywords to filter differently.
When transcluding from Org files into src blocks, markup is escaped automatically:
Source file (notes.org):
* Heading in source
** Sub-heading
#+KEYWORD: value
Regular text.
After transclusion into src block:
#+HEADER: :transclude [[file:notes.org::*Heading in source]]
#+begin_src org
,,* Heading in source
,,** Sub-heading
,,#+KEYWORD: value
Regular text.
Notice the commas before * and #+ characters. This prevents Org from
interpreting them as markup. Without escaping, the #+KEYWORD line would close
the src block prematurely.
Escaping is enabled by default for Org sources (file: links to .org files, id:
links, etc.). Control per-block with :transclude-escape-org:
#+HEADER: :transclude [[file:notes.org]]
#+HEADER: :transclude-escape-org nil
#+begin_src org
#+end_src
Or disable globally:
(setq org-transclusion-blocks-escape-org-sources nil)Non-Org sources (Python, text files, etc.) are never escaped automatically. If
for example a markdown file or docstring contains * or other elements which can be
interpreted as org elements, you can escape them by using :transclude-escape-org t.
org-transclusion uses #+transclude: keywords that exist outside block structure,
while the transcluded content is being displayed, the transclude keyword
dissapears:
#+transclude: [[file:file-name.el]] :src elisp :lines 10-15
<content appears, original keyword dissapears>
This creates issues:
- No property inheritance: Can’t set common values in property drawer
- No Babel integration: Can’t combine with
:session,:resultsin src blocks - Volatile content: the source block disappears when transclusion is inactive (unless detached)
- Version control blind: Content not saved to file (unless detached)
Headers work with Org’s existing systems:
Property inheritance:
:PROPERTIES:
:header-args: :transclude [[file:~/research.org]]
:END:
Babel integration:
Csv data excerpt:
#+HEADER: :transclude [[file:data.csv]]
#+HEADER: :transclude-keywords ":lines 1-10"
#+begin_src :results silent :exports both
#+end_src
#+HEADER: :results silent :exports both
#+begin_src python :session analysis
import pandas as pd
data = pd.read_csv('data.csv')
#+end_src
Persistent content (saved to file):
#+HEADER: :transclude [[file:notes.org]]
#+begin_src org
Content remains here when transclusion inactive.
Version control sees it.
#+end_src
Consider orgit-file transclusion links for Git repository content:
#+transclude: [[orgit-file:/home/user/code/project::refs/heads/main::src/core.el::(defun process-data]] :src elisp :thing-at-point sexp
Basic sepparation into headers, while offering some respite, still lacks the ideal form for easier management:
#+HEADER: :transclude [[orgit-file:/home/user/code/project::refs/heads/main::src/core.el::(defun process-data]]
#+HEADER: :transclude-keywords ":thing-at-point sexp"
#+begin_src elisp
#+end_src
Issues:
- Difficult to read (all components concatenated)
- Hard to modify (must reconstruct entire link)
- Error-prone (typos in revision, file path)
- No validation (errors discovered during fetch, not before)
With the transclude-type constructor utilities, we can create headers for this
specific transclusion link type:
#+HEADER: :transclude-type orgit-file
#+HEADER: :orgit-repo ~/code/project
#+HEADER: :orgit-rev main
#+HEADER: :orgit-file src/core.el
#+HEADER: :orgit-search (defun process-data
#+HEADER: :transclude-keyword ":thing-at-point sexp"
#+begin_src elisp
#+end_src
Benefits:
- Readable: Each component labeled semantically
- Modifiable: Change
:orgit-revwithout touching other components - Validated: Catch invalid git refs before fetch attempt
- Inheritable: Set
:orgit-repoin property drawer for entire subtree - Self-documenting: Header names explain purpose
The package provides three headers that work immediately without registration:
Specify complete link directly:
#+HEADER: :transclude [[file:~/notes.org::*Heading]]
#+begin_src org
#+end_src
Accepts any link type org-transclusion supports:
- File links:
[[file:path.org]],[[file:path.org::*Heading]],[[file:path.org::#custom-id]] - ID links:
[[id:uuid]] - Custom links:
[[orgit-file:...]](if org-transclusion-orgit installed)
Pass options to org-transclusion’s keyword parser:
#+HEADER: :transclude [[file:notes.org]]
#+HEADER: :transclude-keywords ":only-contents :lines 10-20"
#+begin_src org
#+end_src
Equivalent to org-transclusion keyword:
#+transclude: [[file:notes.org]] :only-contents :lines 10-20
Common keywords:
:only-contents- Exclude heading title:lines N-M- Transclude line range:level N- Set headline level:exclude-elements "drawer keyword"- Exclude element types:expand-links- Expand relative file paths to absolute
See org-transclusion manual for complete keyword reference.
Override default escaping behavior per block:
#+HEADER: :transclude [[file:notes.org]]
#+HEADER: :transclude-escape-org nil
#+begin_src org
#+end_src
Values:
toryes- Force escaping (prepend commas to*,#+lines)nilorno- Disable escaping- Omitted - Use default (
org-transclusion-blocks-escape-org-sources)
Escaping prevents Org markup in transcluded content from breaking src block structure.
Default behavior (controlled by org-transclusion-blocks-escape-org-sources):
- Org sources (
.orgfiles,id:links): Escaped - Non-Org sources (Python, text, etc.): Not escaped
The package supports any Org block with #+begin_TYPE / #+end_TYPE delimiters:
#+HEADER: :transclude [[file:code-samples.el::(defun process-data]]
#+HEADER: :transclude-keywords ":thing-at-point sexp"
#+begin_src elisp
#+end_src
#+HEADER: :transclude [[file:~/research/literature.org::*Smith 2020]]
#+HEADER: :transclude-keywords ":only-contents"
#+begin_quote
#+end_quote
#+HEADER: :transclude [[file:~/projects/output.log]]
#+HEADER: :transclude-keywords ":lines 1-50"
#+begin_example
#+end_example
#+HEADER: :transclude [[file:~/templates/header.html]]
#+begin_export html
#+end_export
#+HEADER: :transclude [[file:~/glossary.org::*Definition]]
#+begin_definition
#+end_definition
Component-based headers require type registration. The package includes no default registrations - all types are user-defined.
Use components when:
- Links are complex (multiple path segments, revisions, search terms)
- You want validation before content fetch
- You need property inheritance for repeated values
- Links would benefit from semantic decomposition
Continue using :transclude header for simple links.
Say your journal follows a date-based structure:
~/journal/2025/2025-01-15.org
~/journal/2025/2025-01-16.org
You want semantic headers instead of file paths:
#+HEADER: :transclude-type journal
#+HEADER: :journal-year 2025
#+HEADER: :journal-date 01-15
#+begin_src org
#+end_src
Break the link into pieces:
- Year (4 digits, required)
- Date (MM-DD format, required)
Map semantic names to header keywords:
'(:year (:header :journal-year
:required t)
:date (:header :journal-date
:required t))The :year symbol is internal (used in constructor). The :journal-year keyword
appears in headers.
Transform components into file link:
(lambda (components)
(let ((year (plist-get components :year))
(date (plist-get components :date)))
(format "file:~/journal/%s/%s-%s.org"
year year date)))Constructor receives (:year "2025" :date "01-15"), returns
"file:~/journal/2025/2025-01-15.org" (without [[ ]] brackets).
(org-transclusion-blocks-register-type
'journal
'(:year (:header :journal-year
:required t)
:date (:header :journal-date
:required t))
(lambda (components)
(let ((year (plist-get components :year))
(date (plist-get components :date)))
(format "file:~/journal/%s/%s-%s.org"
year year date))))The type is now available. Use it:
#+HEADER: :transclude-type journal
#+HEADER: :journal-year 2025
#+HEADER: :journal-date 01-15
#+begin_src org
#+end_src
Catch format errors early:
(org-transclusion-blocks-register-type
'journal
'(:year (:header :journal-year
:required t
:validator ,(org-transclusion-blocks-make-regexp-validator
"^[0-9]\\{4\\}$" "year (4 digits)"))
:date (:header :journal-date
:required t
:validator ,(org-transclusion-blocks-make-regexp-validator
"^[0-9]\\{2\\}-[0-9]\\{2\\}$" "date (MM-DD)")))
(lambda (components)
(let ((year (plist-get components :year))
(date (plist-get components :date)))
(format "file:~/journal/%s/%s-%s.org"
year year date))))Now typos are caught before fetch:
Header :journal-date: date (MM-DD) must match pattern ^[0-9]\{2\}-[0-9]\{2\}$, got: "1-15"
Components can declare relationships:
Signals error if component missing:
'(:path (:header :my-path
:required t))Error if :my-path absent:
Type my-type: required component :my-path (header :my-path) is missing
Warns when shadowed component present:
'(:search (:header :my-search
:shadowed-by (:transclude-lines :transclude-thing)))Warning if :my-search and :transclude-lines both present:
Header :transclude-lines shadows :my-search; latter will be ignored
The :my-search value is ignored when :transclude-lines present.
Signals error if dependency missing:
'(:search (:header :my-search
:requires (:path)))Error if :my-search present but :path absent:
Component :my-search requires :path to be present
Signals error if both present:
'(:mode-a (:header :my-mode-a
:conflicts (:mode-b)))Error if both :my-mode-a and :my-mode-b present:
Components :my-mode-a and :my-mode-b cannot be used together
Control warning display:
(setq org-transclusion-blocks-show-interaction-warnings nil) ; Hide soft conflicts (shadowing)Hard conflicts (requirements, mutual exclusions) always signal errors.
Require non-empty string:
:validator ,(org-transclusion-blocks-make-non-empty-validator "repository path")Error if empty:
Header :orgit-repo: repository path cannot be empty
Match regular expression:
:validator ,(org-transclusion-blocks-make-regexp-validator
"^[0-9]\\{4\\}$" "year")Error if pattern mismatch:
Header :journal-year: year must match pattern ^[0-9]\{4\}$, got: "25"
Use custom predicate function:
:validator ,(org-transclusion-blocks-make-predicate-validator
#'file-exists-p "file path")Error if predicate returns nil:
Header :file-path: invalid file path: "/nonexistent.org"
Chain validators (stops at first error):
:validator ,(org-transclusion-blocks-compose-validators
(org-transclusion-blocks-make-non-empty-validator "path")
(org-transclusion-blocks-make-predicate-validator
#'file-exists-p "path"))First checks non-empty, then checks existence.
Write validator functions:
(defun my-validate-git-ref (value header-key type)
"Validate git reference format."
(unless (string-match-p "^[a-zA-Z0-9/_.-]+$" value)
(user-error "%s"
(org-transclusion-blocks-format-validation-error
header-key
"invalid git ref format"
value
"Expected: branch name, tag, or commit hash"
"Examples: main, v1.0.0, abc1234")))
value)Validator signature: (lambda (value header-key type) ...)
value- String from headerheader-key- Keyword (:my-header)type- Type symbol ('my-type)- Returns - Validated value (possibly transformed)
- Signals -
user-errorwith message on failure
Use org-transclusion-blocks-format-validation-error for consistent formatting.
Fetch and insert content for block at point.
Keybinding suggestion: C-c n t
Behavior:
- Detects construction mode (direct
:transclude, type-specific, etc.) - Runs validators if type-specific components present
- Constructs link from headers
- Fetches content via org-transclusion
- Escapes Org syntax if applicable
- Inserts content into block body
- Shows success indicator (checkmark overlay)
With prefix argument C-u:
- Copies source content instead of transcluding (detached)
- Content is editable, not linked to source
Process all blocks with transclusion headers in buffer or region.
Keybinding suggestion: C-c n T
Accepts scope argument:
nilor'buffer- Entire buffer (default)'subtree- Current subtree only'region- Active region
Returns list of successfully processed block positions.
Test validators without fetching content.
Keybinding suggestion: C-c n v
Useful for:
- Testing validator configurations
- Debugging error messages
- Learning what triggers validation failures
Reports validation success or shows error message.
Display comprehensive documentation for registered type.
Interactive usage: M-x org-transclusion-blocks-describe-type RET journal RET
Shows:
- Component specifications (headers, validators, constraints)
- Interaction relationships (required, shadowed-by, requires, conflicts)
- Constructor function
- Usage example with all components
Output appears in *Help/ buffer.
Show all registered types with component counts.
Interactive usage: M-x org-transclusion-blocks-list-types RET
Example output:
Registered link types: journal 2 components project-file 4 components
Use org-transclusion-blocks-describe-type for detailed information about specific types.
(use-package org-transclusion-blocks
:after org-transclusion
:bind (:map org-mode-map
("C-c n t" . org-transclusion-blocks-add)))This enables:
- Header-based transclusion with
:transclude - Property inheritance
- Persistent content
- Org syntax escaping
(use-package org-transclusion-blocks
:after org-transclusion
:custom
;; Show warnings for shadowed components (default: t)
(org-transclusion-blocks-show-interaction-warnings t)
;; Success indicator duration in seconds (default: 2.0)
(org-transclusion-blocks-indicator-duration 3.0)
;; Enable Org syntax escaping for Org sources (default: t)
(org-transclusion-blocks-escape-org-sources t)
:bind (:map org-mode-map
("C-c n t" . org-transclusion-blocks-add)
("C-c n T" . org-transclusion-blocks-add-all)
("C-c n v" . org-transclusion-blocks-validate-current-block)))Default: t
Whether to show warnings for component interactions.
When t:
- Warns about shadowed components (
"Header :foo shadows :bar") - Warns about mode conflicts (mixed construction forms)
- Still signals errors for hard conflicts (requirements, mutual exclusions)
When nil:
- Only signals errors for hard conflicts
- No warnings for soft conflicts
Default: 2.0
Seconds to display success indicator (checkmark overlay) after content insertion.
Set to 0 to disable indicator entirely.
Default: 'org-transclusion-blocks-fetched
Text property name for storing fetch timestamp on transcluded content.
Used for future refresh functionality. Not user-visible.
Default: t
Whether to escape Org syntax when transcluding from Org files.
When t (recommended):
- Automatically escapes content from
.orgfiles,id:links, etc. - Prevents
*(headlines),#+(keywords) from breaking src block structure - Prepends comma to lines starting with Org markup
When nil:
- No escaping
- User must manually escape or risk syntax errors
Override per-block with :transclude-escape-org header.
Does not affect non-Org sources (Python, text, etc.).
This package is a link construction framework. org-transclusion is the content extraction framework. The relationship:
- org-transclusion-blocks: Component headers → Link string
- org-transclusion: Link string → Content extraction
All org-transclusion capabilities work:
:only-contents- Exclude heading titles:lines- Line range extraction:level- Headline level adjustment:exclude-elements- Filter element types:expand-links- Expand relative paths- Live sync (if enabled)
- Export handling
Pass these via :transclude-keywords header:
#+HEADER: :transclude [[file:notes.org]]
#+HEADER: :transclude-keywords ":only-contents :level 2"
#+begin_src org
#+end_src
The upcoming transient branch of org-transclusion generalizes transclusion to
any link type via org-link-open. This benefits our component-based approach:
Before transient:
- Specialized link types require extension packages (
org-transclusion-orgit) - Each extension implements custom navigation logic
After transient:
- org-transclusion handles any link type via standard
org-link-open - Component-based headers construct standard Org links
- No extension packages needed (unless link type itself requires one, like
orgit)
Your component headers construct standard links. org-transclusion navigates to them.
org-transclusion handles content fetching and extraction. org-transclusion-blocks constructs links, org-transclusion navigates and fetches.
Install via MELPA or GNU ELPA:
(use-package org-transclusion)orgit provides orgit-file: link type for
Git repository navigation. Useful with component-based headers:
#+HEADER: :transclude-type orgit-file
#+HEADER: :orgit-repo ~/code/project
#+HEADER: :orgit-rev v1.2.0
#+HEADER: :orgit-file src/core.el
#+begin_src elisp
#+end_src
Install via MELPA:
(use-package orgit)Extension enabling org-transclusion to fetch from orgit-file: links. Required if
using pre-transient org-transclusion with orgit links.
- Install org-transclusion (handles content fetching)
- Install org-transclusion-blocks (adds header-based construction)
- Optionally: Install orgit-file for Magit file blob links
- Optionally: Install org-transclusion-git
Packages compose. Each adds capability without replacing others.
Symptom: Command reports no headers after invoking org-transclusion-blocks-add.
Diagnosis:
- Check block has at least one recognized header:
:transclude(direct link):transclude-type(component-based)
- Verify header syntax:
#+HEADER: :transclude [[file:path.org]] ; Correct #+HEADER :transclude [[file:path.org]] ; WRONG (missing colon) #+HEADER: transclude [[file:path.org]] ; WRONG (missing colon before keyword)
Solution: Add recognized header with correct syntax.
Symptom: Error message indicates missing required component.
Diagnosis: Registered type declares component as :required t but header absent.
Solution:
Option 1 - Add missing component:
#+HEADER: :transclude-type journal
#+HEADER: :journal-year 2025 ; Add this
#+HEADER: :journal-date 01-15
Option 2 - Use different construction form:
#+HEADER: :transclude [[file:~/journal/2025/2025-01-15.org]]
Symptom: org-transclusion reports fetch failure.
Diagnosis: Link is constructed but target is unreachable.
Investigation:
Step 1 - Test link directly:
#+HEADER: :transclude [[file:~/notes.org::*Heading]]
^ Place point here
Press C-c C-o (org-open-at-point). If this fails, link is invalid.
Step 2 - Check link type support:
Some link types require org-transclusion extensions:
orgit-file:- Requiresorg-transclusion-orgit(pre-transient) ortransientbranchid:- Built-in supportfile:- Built-in support
Check registered handlers: M-: org-transclusion-add-functions
Step 3 - Enable debug output:
(setq org-transclusion-debug t)Retry org-transclusion-blocks-add. Check *Messages/ buffer for diagnostics.
Step 4 - Verify target exists:
Navigate manually to target:
- Open file
- Search for heading/pattern
- Confirm content exists
If target missing, link works but fetch returns empty.
Solution: Fix link or target based on diagnosis.
Symptom: Warning about shadowed component.
Diagnosis: Component declares :shadowed-by (:foo) and both headers present.
Example:
#+HEADER: :transclude-type my-type
#+HEADER: :my-search "pattern" ; Will be ignored
#+HEADER: :transclude-lines 10-20 ; Takes precedence
Understanding: The :transclude-lines header overrides :my-search completely.
The search value is never used.
Solution:
Option 1 - Remove shadowed header:
#+HEADER: :transclude-type my-type
#+HEADER: :transclude-lines 10-20 ; Use this
Option 2 - Remove shadowing header:
#+HEADER: :transclude-type my-type
#+HEADER: :my-search "pattern" ; Use this
Option 3 - Disable warnings:
(setq org-transclusion-blocks-show-interaction-warnings nil)Symptom: Error “end of file during parsing” when using search patterns in src blocks.
Diagnosis: Babel evaluates values starting with ( as Elisp expressions.
Example problem:
#+HEADER: :orgit-search (defun process-data
#+begin_src elisp
#+end_src
Babel tries to evaluate (defun process-data and fails (incomplete s-expression).
Solution 1 - Quote the search term:
#+HEADER: :orgit-search "(defun process-data"
#+begin_src elisp
#+end_src
Solution 2 - Use complete s-expression:
#+HEADER: :orgit-search (defun process-data (x y) (+ x y))
#+begin_src elisp
#+end_src
Solution 3 - Use validator that catches incomplete expressions:
See “Custom Validators” section for search pattern validation example.
Note: This issue only affects src blocks (Babel processes headers). Other block types (quote, example, etc.) don’t evaluate headers, so search patterns work without quoting.
Symptom: Transcluded content has unexpected commas before * or #+ lines.
Example:
* This line has comma
#+KEYWORD: also has comma
Diagnosis: Org syntax escaping is active.
Understanding: Escaping prevents Org from interpreting headlines and keywords
in src blocks. Without escaping, / Heading would be treated as a headline,
#+KEYWORD would close the block.
Solution:
If you want unescaped content (and accept the risk):
#+HEADER: :transclude [[file:notes.org]]
#+HEADER: :transclude-escape-org nil
#+begin_src org
#+end_src
Or disable globally:
(setq org-transclusion-blocks-escape-org-sources nil)Note: Disabling escaping for Org sources in src blocks will cause syntax errors if content contains headlines or keywords. Use non-src block types (quote, example) if you need literal Org content.
org-transclusion (keyword-based):
#+transclude: [[file:/path/to/file.org::*Heading]] :only-contents
org-transclusion-blocks (header-based):
#+HEADER: :transclude [[file:/path/to/file.org::*Heading]]
#+HEADER: :transclude-keywords ":only-contents"
#+begin_src org
#+end_src
Key Differences:
| Aspect | org-transclusion | org-transclusion-blocks |
|---|---|---|
| Syntax | #+transclude: keyword | #+HEADER: arguments |
| Display | Overlay (volatile) | Persistent in buffer |
| Version control | Content not saved | Content saved to file |
| Property inheritance | Not supported | Full support via :PROPERTIES: |
| Babel integration | Not applicable | Full support (:session, etc.) |
| Block types | Any location | Org blocks only |
| Offline access | Requires active transclusion | Works offline (content persisted) |
Choose org-transclusion when:
- You want live-synced overlays
- Content should not persist in file
- You prefer
#+transclude:keyword syntax
Choose org-transclusion-blocks when:
- You want persistent content (version control, offline)
- You need property inheritance
- You want Babel integration (src blocks)
- Complex links benefit from component decomposition
- You want validation before fetch
Both use same content-fetching machinery (org-transclusion). They differ in interface and content persistence.
- org-transclusion repository - Content fetching framework
- org-transclusion manual - Comprehensive guide to transclusion features
- Org manual: Working with Source Code - Babel and source blocks
- Org manual: Link Format - Link syntax and conventions
- Org manual: Header Arguments - Property inheritance and header usage
See testing/examples/ directory in repository for:
- Custom link type registrations
- Validator implementations
- Constructor patterns
- Integration with external tools
- Property inheritance workflows
- org-transclusion - Content fetching and overlay management
- orgit - Git repository links for Org
- orgit-file - Org links to files in Git repositories
- org-transclusion-orgit - transclusion support for orgit-file and other orgit link types
Contributions welcome. Please:
- Open issue describing feature or bug
- Reference issue in pull request
- Add tests for new functionality
- Update documentation for user-visible changes
- org-transclusion by Noboru Ota for content-fetching infrastructure
GPLv3 or later