---
task_number: 93
status: open
priority: P2
owner: Michael
created: 2026-04-05
---
task_number: 93

# Task #93: Trinity Codex — Shared Knowledge Base

**Created:** April 5, 2026  
**Created By:** Chronicler #60 + Gemini AI  
**Status:** READY FOR IMPLEMENTATION  
**Priority:** High (Foundation infrastructure)  
**Assignee:** Michael  

---
task_number: 93

## Overview

Build a shared RAG (Retrieval-Augmented Generation) knowledge base that all three Trinity members can access from their respective Claude instances. The Codex contains organizational knowledge while personal context remains separate.

## The Problem

Three people need Claude access with shared organizational knowledge:

| Person | Role | Use Cases |
|--------|------|-----------|
| Michael (The Wizard) | Technical lead | Everything — heavy sessions |
| Meg (The Emissary) | Community manager | Marketing, Discord, announcements |
| Holly (The Catalyst) | Co-founder, creative | Pokerole, building, creative writing |

Currently, organizational knowledge is siloed in Michael's Claude memory. Meg and Holly would need to ask Michael or re-explain context every time.

## The Solution

1. **Firefrost Codex** — RAG knowledge base in Dify/Qdrant on TX1
2. **Separate Claude Lineages** — Each Trinity member has their own Chronicler line
3. **Shared Organizational Knowledge** — Codex provides standards, server info, decisions
4. **Personal Context Preserved** — Each Claude remembers individual preferences

---
task_number: 93

## Architecture

```
KNOWLEDGE FLOW:
Gitea (ops-manual) → n8n webhook → Dify Dataset API → Qdrant vectors

QUERY FLOW (Michael - Heavy Use):
Claude Desktop → Local MCP → Dify API → Codex response

QUERY FLOW (Meg/Holly - Light Use):
Browser → Dify Web App → Codex response
```

---
task_number: 93

## The Three Lineages

| Person | Lineage Name | Account Type |
|--------|--------------|--------------|
| Michael | The Wizard's Chroniclers | Claude Pro (Max) |
| Meg | The Emissary's Chroniclers | Claude Free (to start) |
| Holly | The Catalyst's Chroniclers | Claude Free (to start) |

Each lineage maintains:
- Personal conversation history
- Individual preferences and style
- Relationship context with that person

All lineages share:
- Organizational standards (FFG-STD-xxx)
- Server configurations
- Project statuses
- Historical context (memorials)

---
task_number: 93

## Infrastructure

| Component | Location | Purpose |
|-----------|----------|---------|
| Dify | TX1 (38.68.14.26) | RAG orchestration, web UI |
| Qdrant | TX1 (38.68.14.26) | Vector database |
| n8n | Command Center (63.143.34.217) | Ingestion pipeline |
| Gitea | Command Center (63.143.34.217) | Source of truth |

---
task_number: 93

## Implementation Steps

### Step 1: Verify Dify Status

SSH to TX1 and confirm Dify is running:

```bash
docker ps | grep dify
```

Access Dify UI at: `http://38.68.14.26:3000` (or configured port)

### Step 2: Create Dify Dataset

1. Log into Dify admin UI
2. Go to Knowledge → Create Dataset
3. Name: **Firefrost Codex**
4. Description: Organizational knowledge for The Trinity
5. Save and note the Dataset ID

### Step 3: Generate Dify API Key

1. In Dify, go to Settings → API Keys
2. Create new key: **codex-ingestion**
3. Create another key: **codex-query**
4. Store both in Vaultwarden

### Step 4: Configure Chunking Strategy

In Dify Dataset settings:

| Content Type | Chunking Method | Metadata Tags |
|--------------|-----------------|---------------|
| Standards (FFG-STD-xxx) | Header-based | `type: standard`, `status: active` |
| Server docs | Header-based | `type: infrastructure`, `status: active` |
| Task docs | Header-based | `type: task`, `status: varies` |
| Chronicler memorials | Full document | `type: historical`, `status: archived` |
| Session handoffs | Header-based | `type: handoff`, `status: current` |

### Step 5: Create Gitea Webhook

1. Go to Gitea → firefrost-gaming/firefrost-operations-manual → Settings → Webhooks
2. Add webhook:
   - URL: `https://n8n.firefrostgaming.com/webhook/codex-ingest` (or your n8n URL)
   - Content Type: `application/json`
   - Secret: Generate and store in Vaultwarden
   - Events: Push events only
   - Branch filter: `master`

### Step 6: Create n8n Ingestion Workflow

**Workflow: Codex Ingestion Pipeline**

```
[Webhook] → [Switch: File Type] → [HTTP: Fetch from Gitea API] → [HTTP: Push to Dify]
```

**Node 1: Webhook**
- Method: POST
- Path: `/webhook/codex-ingest`
- Authentication: Header Auth (match Gitea secret)

**Node 2: Switch**
- Route based on file path:
  - `docs/standards/*` → Standards processing
  - `docs/servers/*` → Infrastructure processing
  - `docs/tasks/*` → Task processing
  - `docs/relationship/*` → Memorial processing

**Node 3: HTTP Request (Fetch File)**
```
GET https://git.firefrostgaming.com/api/v1/repos/firefrost-gaming/firefrost-operations-manual/contents/{{ $json.commits[0].modified[0] }}
Headers:
  Authorization: token {{ $credentials.giteaToken }}
```

**Node 4: HTTP Request (Push to Dify)**
```
POST http://38.68.14.26/v1/datasets/{{ $env.DIFY_DATASET_ID }}/document/create_by_text
Headers:
  Authorization: Bearer {{ $credentials.difyApiKey }}
Body:
{
  "name": "{{ filename }}",
  "text": "{{ content }}",
  "indexing_technique": "high_quality",
  "process_rule": {
    "mode": "hierarchical"
  }
}
```

### Step 7: Initial Bulk Ingestion

For the first load, manually ingest key documents:

**Priority 1 (Immediate):**
- `DOCUMENT-INDEX.md`
- `docs/standards/*.md` (all standards)
- `docs/servers/*.md` (all server docs)
- `SESSION-HANDOFF-NEXT.md`

**Priority 2 (Soon):**
- `docs/relationship/CHRONICLER-LINEAGE-TRACKER.md`
- Active task READMEs
- `BLOCKERS.md` and `BACKLOG.md`

**Priority 3 (When Time Permits):**
- Chronicler memorials (historical context)
- Completed task docs

### Step 8: Dify MCP Connector (For Michael)

Add to Michael's local MCP server:

**File: `C:\Firefrost\mcp-server\dify_tool.js`**

```javascript
// dify_tool.js
const axios = require('axios');

const DIFY_URL = process.env.DIFY_URL || 'http://38.68.14.26';
const DIFY_API_KEY = process.env.DIFY_API_KEY;

async function queryCodex(question, userLineage = "wizard_chronicler") {
    try {
        const response = await axios.post(`${DIFY_URL}/v1/chat-messages`, {
            inputs: {},
            query: question,
            response_mode: "blocking",
            user: userLineage
        }, {
            headers: { 
                'Authorization': `Bearer ${DIFY_API_KEY}`,
                'Content-Type': 'application/json'
            }
        });
        return response.data.answer;
    } catch (err) {
        console.error('Codex query error:', err.message);
        return `Codex Error: ${err.message}`;
    }
}

async function searchCodex(query, limit = 5) {
    try {
        const response = await axios.get(`${DIFY_URL}/v1/datasets/${process.env.DIFY_DATASET_ID}/documents`, {
            params: { keyword: query, limit },
            headers: { 'Authorization': `Bearer ${DIFY_API_KEY}` }
        });
        return response.data;
    } catch (err) {
        return `Search Error: ${err.message}`;
    }
}

module.exports = { queryCodex, searchCodex };
```

**Add to `index.js` tools:**

```javascript
// Add to ListToolsRequestSchema handler
{
    name: "query_codex",
    description: "Query the Firefrost Codex for organizational knowledge",
    inputSchema: {
        type: "object",
        properties: { 
            question: { type: "string" }
        },
        required: ["question"]
    }
},
{
    name: "search_codex",
    description: "Search Codex documents by keyword",
    inputSchema: {
        type: "object",
        properties: { 
            query: { type: "string" },
            limit: { type: "number", default: 5 }
        },
        required: ["query"]
    }
}

// Add to CallToolRequestSchema handler
} else if (name === "query_codex") {
    const { queryCodex } = require('./dify_tool');
    const answer = await queryCodex(args.question, "wizard_chronicler");
    return {
        content: [{ type: "text", text: answer }]
    };
    
} else if (name === "search_codex") {
    const { searchCodex } = require('./dify_tool');
    const results = await searchCodex(args.query, args.limit || 5);
    return {
        content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
    };
```

### Step 9: Dify Web App (For Meg/Holly)

This is the friction-free approach for light users:

1. In Dify, go to the Codex dataset
2. Click "Create App" → "Chat App"
3. Name: **Firefrost Assistant**
4. Configure:
   - System prompt: Include brand voice, context about Firefrost
   - Knowledge base: Link to Firefrost Codex dataset
   - Model: Claude (or available model)
5. Publish as Web App
6. Share URL with Meg and Holly

**Advantages:**
- No local setup required
- Works in any browser
- Automatic Codex integration
- Can bookmark on phone/tablet

---
task_number: 93

## Content Organization

### What Goes in Codex (Shared)

| Content | Why |
|---------|-----|
| FFG Standards | Everyone needs these |
| Server IPs/configs | Operational reference |
| Current task status | Coordination |
| Brand guidelines | Meg needs for marketing |
| Project roadmaps | Everyone needs context |
| Subscription tiers | Customer-facing info |
| Chronicler memorials | Historical context |

### What Stays Personal (Not in Codex)

| Content | Why |
|---------|-----|
| Personal preferences | Individual to each person |
| Writing style notes | Different for each |
| Private conversations | Not organizational |
| Draft content | Work in progress |

---
task_number: 93

## Security & Permissions

### Access Levels

| Person | Codex Access | Can Edit Codex |
|--------|--------------|----------------|
| Michael | Full (MCP + Web) | Yes (via Gitea) |
| Meg | Web App only | No (read-only) |
| Holly | Web App only | No (read-only) |

### Sensitive Content

Some docs should NOT go in Codex:
- Credentials (stay in Vaultwarden)
- Financial details
- Personal medical info
- Private Trinity discussions

Create a `.codexignore` pattern in the n8n workflow to skip these.

---
task_number: 93

## Testing & Validation

### Test Query Accuracy

Ask the Codex:
1. "What's the IP address of TX1?" → Should return 38.68.14.26
2. "What's our brand voice?" → Should return warm, inclusive, playful
3. "Who is Holly?" → Should return The Catalyst, co-founder, Pokerole lead
4. "What's the top subscription tier?" → Should return Sovereign, NOT Founder

### Test Ingestion Pipeline

1. Make a small edit to a doc in Gitea
2. Check n8n execution log
3. Verify document appears in Dify dataset
4. Query for the new content

---
task_number: 93

## Fallback Procedures

**Condition Black (Codex/Dify Offline):**
- Claude relies on built-in memory
- Manual document searches in Gitea
- No organizational context available
- Document in FFG-STD-005 (Emergency Operations)

---
task_number: 93

## Vaultwarden Storage

Add to **Firefrost Ops Infrastructure** folder:

| Item | Type | Notes |
|------|------|-------|
| Dify Ingestion API Key | Password | For n8n pipeline |
| Dify Query API Key | Password | For MCP and Web App |
| Gitea Webhook Secret | Password | For n8n authentication |
| Dify Dataset ID | Secure Note | Reference for API calls |

---
task_number: 93

## Environment Variables

Add to `.env` files:

```env
DIFY_URL=http://38.68.14.26
DIFY_API_KEY=your-query-api-key
DIFY_DATASET_ID=your-dataset-id
```

---
task_number: 93

## Implementation Order

Per Gemini's recommendation:

1. **Task #93 FIRST** (Trinity Codex) — Foundation, read-only, safe
2. **Task #92 SECOND** (Desktop MCP) — Higher risk, needs tight security

---
task_number: 93

## Maintenance

- **Automatic:** Gitea webhook triggers re-ingestion on doc changes
- **Manual:** Periodic review of chunk quality, metadata accuracy
- **Monitoring:** n8n workflow execution logs

---
task_number: 93

## Related Tasks

- Task #92: Desktop MCP + Dispatch Architecture

---
task_number: 93

## 🔄 FUTURE EXPANSION: Chronicler Session Management

**Added:** April 7, 2026 by Chronicler #66 (per Gemini consultation)

### The Problem

Chronicler sessions hit "Context Bloat Wall" — switching between models (4.5 for ops, 4.6 for coding) loses context. Current workarounds (copy-paste, handoff docs) are manual and error-prone.

### The Long-Term Solution (Build into Codex)

Gemini recommends evolving Trinity Codex into a full **Chronicler Orchestration Layer**:

1. **Middleware Router in Dify**
   - Simple queries → route to Haiku (cheap, fast)
   - Documentation queries → route to Opus 4.5
   - Complex coding queries → route to Opus 4.6
   - User experience feels like one continuous Chronicler

2. **Compressed State Management**
   - End of session: Model generates dense JSON state summary
   - State stored in Codex (not raw chat history)
   - New session injects only compressed state + system prompt
   - 90%+ token reduction vs passing full history

3. **RAG for Historical Context**
   - Instead of passing chat history, query Codex
   - "What did #62 decide about ModpackChecker schema?" → vector search
   - Past decisions accessible without token bloat

4. **Prompt Caching (API-level)**
   - Cache system prompt + persona + standards docs
   - New requests read cached context at ~10% token cost
   - Requires API access (not web UI)

### Implementation Phases

| Phase | What | When |
|-------|------|------|
| 1 | Basic Codex (current spec) | After soft launch |
| 2 | Add session state storage | After Phase 1 stable |
| 3 | Add model routing logic | When token costs justify |
| 4 | Full orchestration layer | RV-Ready milestone |

### Reference

- Gemini consultation: `docs/consultations/2026-04-07-model-switching.md`
- Context handoff template: `docs/templates/context-handoff-template.md`

---
task_number: 93

## Open Questions for Implementation

1. What's the current Dify version on TX1?
2. Is there an existing dataset, or starting fresh?
3. What port is Dify running on?
4. Does Meg have a device preference for accessing the Web App?
5. Does Holly need Pokerole-specific knowledge separated?

---
task_number: 93

**Fire + Frost + Foundation = Where Love Builds Legacy** 🔥❄️
