← Back to articles

ARF - Agents Router Framework for Hierarchical Context Management

Path: Computer Tech/AI/ML/ARF - Agents Router Framework for Hierarchical Context Management.mdUpdated: 2/3/2026

ARF - Agents Router Framework for Hierarchical Context Management

ARF (Agents Router Framework) is a hierarchical context management system for AI coding agents that automatically discovers and routes to specialized AGENTS.md files across multiple projects. Instead of maintaining a single monolithic context file, ARF enables modular, project-specific agent contexts that scale as your codebase grows.

Problem Solved: When working across multiple repositories (PhD dissertation, NNT compiler, educational vault, games), manually managing which AGENTS.md file to load becomes tedious and error-prone.

ARF Solution: Auto-discovery + keyword-based routing + single command maintenance

System Architecture

~/AGENTS.md (Root Router)
β”œβ”€ Auto-generated routing table
β”œβ”€ Scans ~/Code/github.com/theslyprofessor/
β”œβ”€ Discovers all nested AGENTS.md files
└─ Routes based on keyword matching

~/Code/github.com/theslyprofessor/
β”œβ”€ PhD/AGENTS.md (dissertation context)
β”œβ”€ nnt/AGENTS.md (compiler context)
β”œβ”€ nnt-docs/AGENTS.md (React components context)
β”œβ”€ midimaze/AGENTS.md (vault management context)
β”‚   β”œβ”€ Audio Discovery/AGENTS.md (song analysis)
β”‚   └─ _Nakul/
β”‚       β”œβ”€ 3. SWC Actions/AGENTS.md (teaching)
β”‚       └─ 5. Coding Actions/AGENTS.md (development)
β”‚           β”œβ”€ NNT Ecosystem/AGENTS.md (notation tools)
β”‚           β”œβ”€ Obsidian/AGENTS.md (vault workflows)
β”‚           └─ Websites/AGENTS.md (web projects)
└─ plant-id-game/AGENTS.md (game context)

How It Works

1. Auto-Discovery

The ~/arf-update script recursively scans your project directories:

bash
~/arf-update

What it does:

  • Finds all AGENTS.md files in ~/Code/github.com/theslyprofessor/
  • Extracts metadata from each file:
    • YAML frontmatter
    • First H1 heading (title)
    • Purpose/description section
  • Infers keywords from:
    • Directory path components
    • File title words
    • Description content

2. Keyword Generation

Keywords are algorithmically extracted, not manually assigned:

Example: ~/Code/github.com/theslyprofessor/nnt/AGENTS.md

  • Path keywords: nnt, compiler, coding
  • Title: "AGENTS.md - nnt Compiler Repository Guidelines"
  • Keywords extracted: nnt, compiler, repository, guidelines
  • Final keywords (top 5): coding, compiler, nnt

3. Routing Table Generation

ARF builds a markdown table in ~/AGENTS.md:

markdown
| If user asks about... | Load this context |
|-----------------------|-------------------|
| coding, compiler, nnt | `~/Code/.../nnt/AGENTS.md` |
| coding, dissertation, phd | `~/Code/.../PhD/AGENTS.md` |
| content, educational, vault | `~/Code/.../midimaze/AGENTS.md` |

4. Context Loading

When you (or OpenCode) work on a task:

User: "Help me debug the NNT compiler's parser" OpenCode: Matches keywords nnt, compiler β†’ Loads nnt/AGENTS.md Result: Agent has compiler-specific context (TypeScript, Bun, peggy grammar, etc.)

User: "Create an article about reverb plugins" OpenCode: No specific keywords β†’ Uses default β†’ Loads midimaze/AGENTS.md Result: Agent has vault rules, frontmatter templates, article structure patterns

Installation & Setup

1. Create Root Router

Create ~/AGENTS.md with router structure:

markdown
---
created: YYYY-MM-DDTHH:MM:SS-TZ
updated: YYYY-MM-DDTHH:MM:SS-TZ
slug: user-level-router
template_type: agent
---
# AGENTS.md - User-Level Router

## Agent Context Loading (Router)

**Default:** If nothing specified β†’ Load `midimaze/AGENTS.md`

**Table Auto-Generated:** Run `~/arf-update` after adding new AGENTS.md files

| If user asks about... | Load this context |
|-----------------------|-------------------|
| (table will be auto-generated) |

## ARF Maintenance

Run `~/arf-update` to regenerate routing table when:
- Adding new project with AGENTS.md
- Renaming project directories
- Restructuring code organization

2. Install arf-update Script

Create ~/arf-update:

python
#!/usr/bin/env python3
"""
ARF Update Script - Auto-generate routing table for AGENTS.md
Scans all AGENTS.md files and creates dynamic routing table
"""

import os
import re
import sys
from pathlib import Path
from datetime import datetime
import yaml

def extract_frontmatter(content):
    """Extract YAML frontmatter from markdown"""
    match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
    if match:
        try:
            return yaml.safe_load(match.group(1))
        except Exception as e:
            print(f"Warning: Failed to parse frontmatter: {e}", file=sys.stderr)
            return {}
    return {}

def extract_title(content):
    """Extract first H1 heading"""
    match = re.search(r'^#\s+(.+)$', content, re.MULTILINE)
    return match.group(1).strip() if match else "Unknown"

def infer_keywords(file_path, title):
    """Infer keywords from path and title"""
    keywords = set()
    
    # Extract from path
    path_parts = str(file_path).lower().split('/')
    keywords.update(part for part in path_parts 
                   if part not in ['code', 'github.com', 'theslyprofessor', 
                                  'agents.md', '_nakul'])
    
    # Extract from title
    title_words = re.findall(r'\b[a-z]{4,}\b', title.lower())
    keywords.update(w for w in title_words 
                   if w not in ['agents', 'agent', 'guidelines', 
                               'context', 'repository'])
    
    return sorted(list(keywords)[:8])

def scan_agents_files(base_path):
    """Scan for all AGENTS.md files and extract metadata"""
    agents_files = []
    base_path = Path(base_path).expanduser()
    
    for agents_file in sorted(base_path.rglob("AGENTS.md")):
        try:
            content = agents_file.read_text()
            title = extract_title(content)
            rel_path = agents_file.relative_to(Path.home())
            keywords = infer_keywords(rel_path, title)
            
            agents_files.append({
                'path': f"~/{rel_path}",
                'keywords': keywords
            })
        except Exception as e:
            print(f"Warning: Failed to process {agents_file}: {e}", 
                  file=sys.stderr)
    
    return agents_files

def generate_routing_table(agents_files):
    """Generate markdown routing table"""
    agents_files.sort(key=lambda x: x['path'])
    
    table = []
    table.append("| If user asks about... | Load this context |")
    table.append("|-----------------------|-------------------|")
    
    for agent in agents_files:
        if agent['path'] == "~/AGENTS.md":
            continue  # Skip root router
        
        keywords_str = ", ".join(agent['keywords'][:5]) if agent['keywords'] else "general"
        table.append(f"| {keywords_str} | `{agent['path']}` |")
    
    return "\n".join(table)

def update_root_agents_md(agents_files, root_path):
    """Update root AGENTS.md with new routing table"""
    root_file = Path(root_path).expanduser()
    
    if not root_file.exists():
        print(f"Error: {root_file} not found", file=sys.stderr)
        return False
    
    content = root_file.read_text()
    new_table = generate_routing_table(agents_files)
    
    # Replace table between router header and next section
    pattern = r'(## Agent Context Loading \(Router\).*?\n\n\*\*Default:\*\*.*?\n\n)(.*?)(\n\n##)'
    
    def replacer(match):
        return match.group(1) + new_table + match.group(3)
    
    updated_content, count = re.subn(pattern, replacer, content, flags=re.DOTALL)
    
    if count == 0:
        print("Warning: Could not find routing table section", file=sys.stderr)
        return False
    
    # Update timestamp
    updated_content = re.sub(
        r'updated: .*',
        f'updated: {datetime.now().strftime("%Y-%m-%dT%H:%M:%S%z")}',
        updated_content
    )
    
    root_file.write_text(updated_content)
    print(f"βœ“ Updated {root_file}")
    print(f"βœ“ Added {len(agents_files)-1} agent contexts to routing table")
    return True

def main():
    print("ARF Update - Scanning for AGENTS.md files...")
    print()
    
    base_path = "~/Code/github.com/theslyprofessor"
    agents_files = scan_agents_files(base_path)
    
    print(f"Found {len(agents_files)} AGENTS.md files")
    print()
    
    root_path = "~/AGENTS.md"
    success = update_root_agents_md(agents_files, root_path)
    
    if success:
        print()
        print("βœ“ ARF routing table updated successfully")
    else:
        print()
        print("βœ— Failed to update routing table")
        sys.exit(1)

if __name__ == "__main__":
    main()

Make executable:

bash
chmod +x ~/arf-update

3. Create Project AGENTS.md Files

For each project, create an AGENTS.md file:

yaml
---
created: YYYY-MM-DDTHH:MM:SS-TZ
updated: YYYY-MM-DDTHH:MM:SS-TZ
slug: project-slug
template_type: agent
---
# AGENTS.md - Project Name

## Purpose
Brief description of what this project is and what the AI should know.

## Tech Stack
- Languages
- Frameworks
- Tools

## Project Structure

src/ β”œβ”€β”€ components/ β”œβ”€β”€ utils/ └── tests/


## Coding Standards
[Project-specific guidelines]

4. Run Discovery

bash
~/arf-update

Expected output:

ARF Update - Scanning for AGENTS.md files...

Found 14 AGENTS.md files

βœ“ Updated /Users/you/AGENTS.md
βœ“ Added 13 agent contexts to routing table

βœ“ ARF routing table updated successfully

Usage Patterns

Adding New Project

  1. Create project with AGENTS.md:
bash
cd ~/Code/github.com/theslyprofessor/my-new-project
touch AGENTS.md
# Edit AGENTS.md with project context
  1. Register with ARF:
bash
~/arf-update
  1. Verify registration:
bash
grep "my-new-project" ~/AGENTS.md

Output:

| my-new-project, [keywords] | `~/Code/.../my-new-project/AGENTS.md` |

Renaming Project Directory

bash
mv ~/Code/github.com/theslyprofessor/old-name ~/Code/github.com/theslyprofessor/new-name
~/arf-update

ARF automatically updates paths in routing table.

Maintenance Schedule

Run ~/arf-update when:

  • βœ… Adding new project
  • βœ… Renaming directories
  • βœ… Restructuring code organization
  • βœ… Keywords seem stale
  • βœ… Quarterly maintenance check

Don't need to run when:

  • ❌ Editing existing AGENTS.md content (paths unchanged)
  • ❌ Adding files to projects (AGENTS.md location unchanged)
  • ❌ Regular coding work

Benefits Over Monolithic AGENTS.md

Scalability

Monolithic: One 5000-line AGENTS.md file

  • Hard to navigate
  • Context overload for AI
  • Slow to parse
  • Merge conflicts in teams

ARF: 14 focused AGENTS.md files (200-700 lines each)

  • Easy to navigate
  • Relevant context only
  • Fast loading
  • Independent updates

Modularity

Monolithic: All projects in one file

markdown
# AGENTS.md
## PhD Dissertation
[300 lines]
## NNT Compiler
[400 lines]
## Midimaze Vault
[500 lines]
...

ARF: Separate files per project

PhD/AGENTS.md (300 lines, LaTeX-specific)
nnt/AGENTS.md (400 lines, TypeScript-specific)
midimaze/AGENTS.md (500 lines, Obsidian-specific)

Maintenance

Monolithic:

  • Manual routing decisions
  • Outdated sections
  • No validation

ARF:

  • Automatic discovery
  • Always current (run script)
  • Built-in validation

Context Efficiency

Monolithic: AI loads 5000 lines every time

  • 90% irrelevant to current task
  • Token waste
  • Slower responses

ARF: AI loads ~300 relevant lines

  • 100% relevant to current task
  • Efficient token usage
  • Faster responses

Real-World Example

Before ARF

markdown
# ~/AGENTS.md (5000 lines)
## PhD Dissertation (LaTeX, BibTeX, academic writing)
## NNT Compiler (TypeScript, Bun, peggy grammar)
## Midimaze Vault (Obsidian, frontmatter, educational content)
## Audio Discovery (song analysis, tagging)
## SWC Teaching (Canvas LMS, gradebook)
## Personal Websites (React, Next.js, deployment)
...

Issue: Working on PhD dissertation loads 4700 irrelevant lines about compilers, Obsidian, Canvas, etc.

After ARF

bash
~/AGENTS.md (150 lines - just routing)
PhD/AGENTS.md (300 lines - LaTeX, academic)
nnt/AGENTS.md (400 lines - TypeScript, grammar)
midimaze/AGENTS.md (500 lines - Obsidian, vault)
...

Result: Working on PhD loads only 300 relevant LaTeX/academic lines.

Context efficiency: 94% improvement (300 vs 5000 lines)

Advanced Features

Nested Routing

Projects can have their own sub-routers:

midimaze/AGENTS.md (vault router)
β”œβ”€ Routes to Audio Discovery/AGENTS.md (song analysis)
β”œβ”€ Routes to _Nakul/3. SWC Actions/AGENTS.md (teaching)
└─ Routes to _Nakul/5. Coding Actions/AGENTS.md (development)
    β”œβ”€ Routes to NNT Ecosystem/AGENTS.md
    β”œβ”€ Routes to Obsidian/AGENTS.md
    └─ Routes to Websites/AGENTS.md

Each level has specialized context for progressively specific tasks.

Default Routing

Configure most-common task as default:

markdown
**Default:** If nothing specified β†’ Load `midimaze/AGENTS.md`

Result: Simple requests ("ma reverb article") automatically get vault context without explicit routing.

Keyword Customization

Override auto-generated keywords in frontmatter:

yaml
---
keywords: [custom, keywords, here]
---

ARF will prefer explicit keywords over inferred ones.

Integration with OpenCode

OpenCode automatically reads ~/AGENTS.md at session start:

  1. User: "Help with NNT compiler"
  2. OpenCode: Reads ~/AGENTS.md routing table
  3. Match: Keywords nnt, compiler β†’ nnt/AGENTS.md
  4. OpenCode: Loads ~/Code/.../nnt/AGENTS.md
  5. Context: TypeScript, Bun, peggy, NNT-specific guidelines
  6. Result: Accurate, context-aware assistance

No user intervention required - routing is transparent.

Troubleshooting

Script Not Found

bash
chmod +x ~/arf-update

PyYAML Not Installed

ARF works without PyYAML (uses basic parsing). To install:

bash
pip3 install pyyaml

Routing Table Not Updating

Check pattern match in ~/AGENTS.md:

markdown
## Agent Context Loading (Router)

**Default:** ...

| If user asks about... | Load this context |
|-----------------------|-------------------|

Pattern must match exactly for replacement to work.

Keywords Not Matching

Run with custom keywords in AGENTS.md frontmatter:

yaml
---
keywords: [exact, keywords, you, want]
---

Future Enhancements

Potential Features

  1. Fuzzy keyword matching - Handle typos, synonyms
  2. Usage analytics - Track which contexts load most
  3. Git hooks integration - Auto-run on commit
  4. JSON export - Machine-readable routing
  5. Web dashboard - Visual routing map
  6. Multi-user routing - Team-specific contexts

Community Extensions

ARF is extensible. You could build:

  • Language-specific routers (Python projects β†’ python-specific AGENTS.md)
  • Framework routers (React projects β†’ react-patterns AGENTS.md)
  • Tool-integrated routing (IDE plugins, CLI tools)

Related Concepts

Conclusion

ARF solves the scaling problem of AI coding agent context management. Instead of a monolithic AGENTS.md file that becomes unmaintainable, ARF provides:

βœ… Automatic discovery of project contexts
βœ… Keyword-based routing to relevant files
βœ… Single-command maintenance (~/arf-update)
βœ… Modular, scalable architecture
βœ… Context efficiency (load only what's needed)

As your codebase grows across multiple repositories, ARF keeps AI assistance accurate and efficient without manual routing overhead.


Next Steps:

  1. Create ~/AGENTS.md root router
  2. Install ~/arf-update script
  3. Add AGENTS.md to each project
  4. Run ~/arf-update
  5. Test with OpenCode: "Help with [project]"

ARF makes multi-project AI assistance practical at scale.