The Local Library Refactor
Date: January 29, 2026 Duration: ~4 hours Issue: Remote graph dependency was fragile Solution: Local @tendril/graph library
The Problem
The knowledge graph kept breaking.
It used some remote mock setup that was… let’s call it “creative.” Every time I touched the component, something would fail. The dependency chain was confusing. Error messages were unhelpful.
I’d spent weeks with a graph that mostly worked. Today I decided to fix it properly.
The Solution
Rip it all out. Build a local library.
New Structure
src/
├── lib/
│ └── tendril/
│ └── graph.ts # Core TendrilGraph class
├── components/
│ └── KnowledgeGraph.astro # Uses local lib
What Changed
Before: Remote dependency with complex mocking After: Local TypeScript library using Cytoscape.js directly
The core class:
// src/lib/tendril/graph.ts
export class TendrilGraph {
private cy: cytoscape.Core;
constructor(container: HTMLElement, options: GraphOptions) {
this.cy = cytoscape({
container,
elements: this.buildElements(options.nodes, options.edges),
style: this.buildStyles(),
layout: this.getLayout()
});
this.bindEvents(options);
}
setPhysics(params: PhysicsParams) { /* ... */ }
filterByType(type: 'all' | 'post' | 'tag') { /* ... */ }
fit(padding?: number) { /* ... */ }
}
Features Added
1. Force-Directed Layout (Working)
Nodes actually repel each other now. Edges act as springs. The physics panel lets you tune gravity and repulsion in real-time.
2. Category-Based Filtering
The graph now excludes category: journal posts. Keeps the main graph clean. Journal entries have their own section.
3. ArgoBox Spectrum Colors
| Category | Color |
|---|---|
| Infrastructure | Blue |
| System | Orange |
| Hardware | Green |
Posts are colored by their category, not just generic blue.
4. Physics Control Panel
Gear icon opens a panel with sliders:
- Center Force
- Repel Force
- Link Force
- Damping
Adjust in real-time, watch the graph reorganize.
The Journal System
While refactoring the graph, I also built the Journal section.
Goal: A place for raw, unpolished content.
Implementation:
- Created
/journalroute - “Glitch/Lab” aesthetic (monospace, dark, warning badges)
- Filters IN
category: journalposts - Main
/blogfilters OUT journal posts
Navigation: Added “Journal” to the global header.
Two kinds of content now:
- Blog: Polished, educational, professional
- Journal: Raw, stream of consciousness, “the struggle”
Content Published Today
| Post | Type | Topic |
|---|---|---|
| incident-reboot-loop.md | Blog | Technical horror story |
| build-swarm-hardening.md | Blog | Architecture deep dive |
| fixing-swarm-monitor.md | Blog | Python/SSH debugging |
| cloudflare-split-brain.md | Journal | Raw debugging log |
Also deleted roblox-on-gentoo.md - keeping focus professional.
Files Created
| File | Purpose |
|---|---|
src/lib/tendril/graph.ts | Core library |
src/pages/journal/index.astro | Journal listing |
scripts/create-post.js | Content automation |
HANDOFF-ARGOBOX-CONTENT.md | AI agent instructions |
CONTENT-PIPELINE.md | Workflow documentation |
What’s Different Now
Before:
- Fragile remote dependency
- Confusing error messages
- No category filtering
- Generic colors
After:
- Local library, fully controlled
- Clear TypeScript errors
- Journal excluded from main graph
- Category-based coloring
- Physics tuning panel
Next Steps
The local library is basically Tendril now. I should extract it properly into the monorepo at ~/Development/tendril/.
The ArgoBox graph is the development lab. Tendril will be the published library.
Same code, different packaging.
Lesson
Sometimes the right fix is to stop patching and rebuild.
Four hours to replace weeks of fragile workarounds.
The graph works now. Actually works. No more “mostly works.”