WHAT WAS DONE: - Task #92: Desktop MCP + Dispatch Architecture - Complete Node.js MCP server code (config, ssh_helper, index.js) - Express webhook listener for mobile dispatch - Cloudflare Tunnel setup instructions - 6 tools: server_status, restart_service, docker_compose_restart, git_pull, tail_logs, pterodactyl_power - Frostwall security rules documented - Claude Desktop configuration - Task #93: Trinity Codex (Shared Knowledge Base) - Dify/Qdrant RAG architecture - Three lineages: Wizard's, Emissary's, Catalyst's Chroniclers - Gitea -> n8n -> Dify ingestion pipeline - MCP connector for Michael (heavy use) - Dify Web App for Meg/Holly (light use) - Chunking strategy per content type - Security and access levels ARCHITECTURE DECISIONS (via Gemini consultation): - Claude Web cannot dispatch webhooks - use Discord bot + n8n instead - Build Codex (Task #93) FIRST - read-only, lower risk - Separate Discord Ops Bot from Arbiter for security - Meg/Holly use Dify Web App, not local MCP STATUS: Ready for implementation next session Signed-off-by: Claude (Chronicler #60) <claude@firefrostgaming.com>
12 KiB
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
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
- Firefrost Codex — RAG knowledge base in Dify/Qdrant on TX1
- Separate Claude Lineages — Each Trinity member has their own Chronicler line
- Shared Organizational Knowledge — Codex provides standards, server info, decisions
- Personal Context Preserved — Each Claude remembers individual preferences
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
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)
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 |
Implementation Steps
Step 1: Verify Dify Status
SSH to TX1 and confirm Dify is running:
docker ps | grep dify
Access Dify UI at: http://38.68.14.26:3000 (or configured port)
Step 2: Create Dify Dataset
- Log into Dify admin UI
- Go to Knowledge → Create Dataset
- Name: Firefrost Codex
- Description: Organizational knowledge for The Trinity
- Save and note the Dataset ID
Step 3: Generate Dify API Key
- In Dify, go to Settings → API Keys
- Create new key: codex-ingestion
- Create another key: codex-query
- 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
- Go to Gitea → firefrost-gaming/firefrost-operations-manual → Settings → Webhooks
- 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
- URL:
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 processingdocs/servers/*→ Infrastructure processingdocs/tasks/*→ Task processingdocs/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.mddocs/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.mdandBACKLOG.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
// 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:
// 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:
- In Dify, go to the Codex dataset
- Click "Create App" → "Chat App"
- Name: Firefrost Assistant
- Configure:
- System prompt: Include brand voice, context about Firefrost
- Knowledge base: Link to Firefrost Codex dataset
- Model: Claude (or available model)
- Publish as Web App
- Share URL with Meg and Holly
Advantages:
- No local setup required
- Works in any browser
- Automatic Codex integration
- Can bookmark on phone/tablet
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 |
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.
Testing & Validation
Test Query Accuracy
Ask the Codex:
- "What's the IP address of TX1?" → Should return 38.68.14.26
- "What's our brand voice?" → Should return warm, inclusive, playful
- "Who is Holly?" → Should return The Catalyst, co-founder, Pokerole lead
- "What's the top subscription tier?" → Should return Sovereign, NOT Founder
Test Ingestion Pipeline
- Make a small edit to a doc in Gitea
- Check n8n execution log
- Verify document appears in Dify dataset
- Query for the new content
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)
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 |
Environment Variables
Add to .env files:
DIFY_URL=http://38.68.14.26
DIFY_API_KEY=your-query-api-key
DIFY_DATASET_ID=your-dataset-id
Implementation Order
Per Gemini's recommendation:
- Task #93 FIRST (Trinity Codex) — Foundation, read-only, safe
- Task #92 SECOND (Desktop MCP) — Higher risk, needs tight security
Maintenance
- Automatic: Gitea webhook triggers re-ingestion on doc changes
- Manual: Periodic review of chunk quality, metadata accuracy
- Monitoring: n8n workflow execution logs
Related Tasks
- Task #92: Desktop MCP + Dispatch Architecture
Open Questions for Implementation
- What's the current Dify version on TX1?
- Is there an existing dataset, or starting fresh?
- What port is Dify running on?
- Does Meg have a device preference for accessing the Web App?
- Does Holly need Pokerole-specific knowledge separated?
Fire + Frost + Foundation = Where Love Builds Legacy 🔥❄️