This document describes the codex-blocks.json index format and how to consume block-level tag data.
The compiled block index is generated by scripts/build-index.mjs and published to the repository root.
// Static exports (quarry.space)
const url = '/assets/codex-blocks.json'
// CDN/GitHub raw
const url = 'https://raw.githubusercontent.com/framerslab/codex/main/codex-blocks.json'{
"generatedAt": "2024-01-15T10:30:00.000Z",
"version": "1.0.0",
"stats": {
"totalStrands": 150,
"totalBlocks": 2340,
"totalTags": 5670,
"uniqueTags": 234,
"worthyBlocks": 1890,
"pendingSuggestions": 456,
"tagsBySource": {
"nlp": 3200,
"llm": 890,
"existing": 1200,
"user": 380
},
"blocksByType": {
"heading": 890,
"paragraph": 1200,
"code": 150,
"list": 80,
"blockquote": 20
}
},
"tagIndex": {
"javascript": [
{ "strandPath": "weaves/technology/js-basics.md", "blockId": "introduction", "confidence": 1.0 },
{ "strandPath": "weaves/technology/js-basics.md", "blockId": "block-45", "confidence": 0.85 }
]
},
"strands": {
"weaves/technology/js-basics.md": {
"path": "weaves/technology/js-basics.md",
"title": "JavaScript Basics",
"blockCount": 15,
"tagCount": 42,
"worthyBlockCount": 12,
"blocks": [
{
"id": "introduction",
"line": 5,
"endLine": 12,
"type": "heading",
"headingLevel": 2,
"headingText": "Introduction",
"tags": ["javascript", "getting-started"],
"suggestedTags": [],
"worthiness": { "score": 0.72 }
}
]
}
}
}interface CodexBlocksIndex {
generatedAt: string // ISO 8601 timestamp
version: string // Semver version
stats: BlockIndexStats
tagIndex: Record<string, TagReference[]>
strands: Record<string, StrandBlockData>
}
interface BlockIndexStats {
totalStrands: number
totalBlocks: number
totalTags: number
uniqueTags: number
worthyBlocks: number
pendingSuggestions: number
tagsBySource: Record<'nlp' | 'llm' | 'existing' | 'user', number>
blocksByType: Record<string, number>
}
interface TagReference {
strandPath: string
blockId: string
confidence: number
}
interface StrandBlockData {
path: string
title: string
blockCount: number
tagCount: number
worthyBlockCount: number
blocks: BlockEntry[]
}
interface BlockEntry {
id: string
line: number
endLine?: number
type: 'heading' | 'paragraph' | 'code' | 'list' | 'blockquote' | 'table' | 'html'
headingLevel?: number
headingText?: string
tags: string[]
suggestedTags: SuggestedTag[]
worthiness?: { score: number; signals?: Record<string, number> }
extractiveSummary?: string
warrantsIllustration?: boolean
}
interface SuggestedTag {
tag: string
confidence: number
source: 'nlp' | 'llm' | 'existing' | 'user'
reasoning?: string
}Frame.dev provides a React hook for consuming block data:
import { useBlockTags, hasBlocksInIndex, getAllBlockTags } from '@/lib/hooks/useBlockTags'
function MyComponent({ strandPath }) {
const {
blocks, // Block array
isLoading, // Loading state
error, // Error object
stats, // { total, tagged, pending, worthy }
getBlockById, // (blockId) => BlockEntry
refetch // () => Promise<void>
} = useBlockTags(strandPath)
if (isLoading) return <Spinner />
if (error) return <Error message={error.message} />
return (
<ul>
{blocks.map(block => (
<li key={block.blockId}>
{block.headingText || block.blockId}
{block.tags.map(tag => <Tag key={tag}>{tag}</Tag>)}
</li>
))}
</ul>
)
}const hasBlocks = await hasBlocksInIndex('weaves/technology/js-basics.md')
// true | falseconst allTags = await getAllBlockTags()
// ['javascript', 'typescript', 'react', ...]const results = await searchBlocksByTag('javascript')
// [{ strandPath, blockId, confidence }, ...]const stats = await getBlockIndexStats()
// { totalStrands, totalBlocks, ... }When running with API routes enabled, these endpoints are available:
Fetch blocks for a strand:
curl "/api/blocks?strandPath=weaves/technology/js-basics.md"Response:
{
"blocks": [
{ "blockId": "introduction", "tags": ["javascript"], ... }
]
}Update block tags (requires authentication):
curl -X POST "/api/blocks/tags" \
-H "Content-Type: application/json" \
-d '{
"action": "accept",
"strandPath": "weaves/technology/js-basics.md",
"blockId": "introduction",
"tag": "es6"
}'Actions: accept, reject, add, remove
The tagIndex object provides an inverted index for tag-based searches:
// Find all blocks tagged with "typescript"
const index = await fetchBlocksIndex()
const typescriptBlocks = index.tagIndex['typescript'] || []
for (const ref of typescriptBlocks) {
console.log(`${ref.strandPath} / ${ref.blockId} (${ref.confidence})`)
}The useBlockTags hook implements caching:
- Memory Cache: Index cached as singleton
- Request Deduplication: Concurrent fetches share same promise
- No IndexedDB: Source of truth is codex repo, not browser
To force refresh:
import { clearBlocksIndexCache } from '@/lib/hooks/useBlockTags'
clearBlocksIndexCache()
await refetch()const { error } = useBlockTags(strandPath)
if (error) {
if (error.message.includes('404')) {
// Index not available - strand may not be processed yet
} else if (error.message.includes('network')) {
// Network error - show offline indicator
}
}- blocks-index.schema.yaml - JSON Schema
- useBlockTags.ts - Hook source
- Block Tagging Guide - User guide
- Block Tagging Schema - Schema reference