I miss reltables, part 3
October 16, 2025
Relative links continue to humble me
Picking up from part 2 of this tale, this post is going to cover how I created the script that creates the markdown snippets that I can reference in my pages. I don't really want to write it myself, but I know exactly what I want it to do. I start with the outline:
- Load
relationships.yaml - Index all document frontmatter from pages/**/*.mdx
- Build lookup structure: { [docPath]: { prerequisites: [], leads_to: [], ... } }
- Handle bidirectional relationships... somehow?
- Validate all relationships (this is my ???? PROFIT step)
- Output to snippets/relationships/name-of-source-file.mdx
I'm not a developer but I do have a philosophy degree
I like writing pseudocode because it helps me check my logic, especially when I'm using AI to do the real coding work.
LOAD relationships.yaml file
PARSE yaml into relationshipTable object
CREATE empty docMetadata map
FOR EACH configured directory: # do I want to hardcode this to just scan /pages? or leave script open ended w/ CLI command defaults set to /pages?
FIND all .mdx files in directory
FOR EACH .mdx file:
READ frontmatter
IF file has title:
STORE { title, subtitle, description, slug } in docMetadata map
USE file path as key (e.g., "learning/guides/boarding-field-explorer")
CREATE empty relationshipLookup map
FOR EACH relationship in relationshipTable.relationships:
ADD relationship to lookup map using topic as key
STORE all relationship types (prerequisites, leads_to, references, etc.)
IF relationshipTable has bidirectional relationships:
FOR EACH bidirectional pair:
ADD relationship type to BOTH documents in the pair
(e.g., if "doc-a" and "doc-b" have "see_also", add each to the other's see_also list)
CREATE snippets/relationships/ directory if it doesn't exist #on the fence about this cause it will only not exist on first run and IDK if I care this much about coding best practices
FOR EACH document in relationshipLookup:
CREATE markdown string starting with "---\n## Related Documentation\n"
IF document has prerequisites:
ADD section header "### Must read first (Prerequisites)"
FOR EACH prerequisite path:
LOOKUP metadata for that path
IF metadata exists:
ADD markdown link with title and optional description
ELSE:
WARN that metadata is missing
IF document has leads_to:
ADD section header "### Build on this knowledge"
[same pattern as prerequisites]
IF document has references:
ADD section header "### Reference while working"
[same pattern]
IF document has advanced:
ADD section header "### Go deeper (Advanced Topics)"
[same pattern]
IF document has see_also:
ADD section header "### Related topics"
[same pattern]
IF document has not_confused_with:
ADD section header "### Often confused with"
FORMAT differently: "**Title** is different - description. [Learn more](link)"
IF any content was added:
ADD footer comment "<!-- Auto-generated by CLI - Do not edit -->"
EXTRACT just the filename from document path
WRITE markdown to snippets/relationships/{filename}.mdx
LOG success message
ELSE:
SKIP this document (no valid relationships)
PRINT summary: "Generated X relationship snippets"
PRINT warnings count
I didn't write much in the way of error handling, cause that'll come as I build the script and test it. So, now my next step is build the script and a test relationship file.
relative links continue to hamper me
Claude did a really good job scripting based on my pseudocode. It nailed it first try. Really. I had a working CLI command with one prompt. The only problem was that I struggle mightily with relative linking and I spent 30 minutes troubleshooting the script cause I was running it from the wrong directory for the file path in my test commands.
a little trouble
I ran into an issue because I had totally forgotten that our slug value in the frontmatter doesn't always match the filepath (by design). So, the output ended up not being in the directories I wanted them to be in. So although, this works and the slugs are unique, it's not what's the most scalable option, so I'll refactor the code to dump things in a mirror directory in /snippets:
What I should have done:
fern/
└── snippets/
└── relationships/
└── sourceDocDirectoryName/
└── sourceDocfilename
What I did:
fern/
└── snippets/
└── relationships/
└── sourceDocSlugName
It doesn't seem like a huge deal, but we also use this approach for our autogenerated card components, and the snippet directories mirroring the doc directories makes it a lot easier to automate on them, and also make it easier to locate snippets in general.
That's basically it. Tomorrow, I'm going to fix my filepath stuff and then put my human touch on the relationships mapping. After that, I might try automating importing the snippets and placing them in our docs. If I do, I'll be sure to report back on that too. I split this post over three installments because I wanted to do a series of shorter blog posts for the modern attention span. At this point in the project, I'd only spent about 3 hours working on this stuff. Four hours in, I'd committed all the CLI updates and had a list of things to dial in the next day.
Postscript: The refactor went well and I made several small improvements. Including adding support for external resources, like our SICK example apps. This was super fun little project. I've decided to do the relationship.yaml tweaks fully by hand because this is a really important part of my AEO/GEO strategy and I want to make sure it shines!