Skip to content
archived Visibility internal Owner erik@uvilo.com Approver _ Created _ Updated _

Libre Agents Spec

Purpose

Implement Alternative E: Master Agent + Programmatic Sync from the Research doc to solve the agent-model binding problem. One master agent serves as the single source of truth; a sync script propagates its configuration to N model-variant agents.


Design Decisions

All open questions resolved. Decisions recorded here for reference.

#DecisionChoice
Q1Master agent visibilityUsable — the master agent IS the GLM 5 Turbo variant, users chat with it directly
Q2MongoDB accessEnvironment variable MONGO_URI (Railway service env)
Q3ModelSpecs in v1Yes — include ModelSpecs configuration in this project
Q4Existing duplicate agentsUpdate in-place by name, preserving _id — never delete, never create with new ID
Q5Naming conventionUvilo Agent <Model> (e.g., “Uvilo Agent GLM 5 Turbo”)
Q6Auto MCP syncNo — MCP servers still need manual addition to the master agent via Agent Builder

Architecture Overview

┌───────────────────────────────────────────────────────────────┐
│  Agent Builder UI                                             │
│  ┌───────────────────────────┐                                │
│  │ Uvilo Agent GLM 5 Turbo   │  ← Master agent (also usable)  │
│  │ Turbo (agent_s5VyS1...)   │    Only agent edited manually  │
│  │ (all tools, instructions, │                                │
│  │  capabilities)            │                                │
│  └───────────┬───────────────┘                                │
│              │                                                │
│              ▼                                                │
│  ┌───────────────────────────┐                                │
│  │ update-agents.ts          │  ← TypeScript sync script         │
│  │ reads agent-sync.yaml     │    (reads master from MongoDB, │
│  │ connects via MONGODB_URI  │    updates variants in-place)  │
│  └───────────┬───────────────┘                                │
│              │                                                │
│              ▼                                                │
│  ┌───────────────────────────────────────────────────┐        │
│  │  Variant Agents (updated in-place, same _id)      │        │
│  │  ┌────────────────────┐ ┌────────────────────┐    │        │
│  │  │ Uvilo Agent        │ │ Uvilo Agent        │    │        │
│  │  │ Opus 4.6           │ │ Sonnet 4.6         │    │        │
│  │  └────────────────────┘ └────────────────────┘    │        │
│  │  ┌────────────────────┐ ┌────────────────────┐    │        │
│  │  │ Uvilo Agent        │ │ Uvilo Agent        │    │        │
│  │  │ GPT 5.1            │ │ GPT 5.4            │    │        │
│  │  └────────────────────┘ └────────────────────┘    │        │
│  │  (identical config to master, different model)    │        │
│  └───────────────────────────────────────────────────┘        │
│              │                                                │
│              ▼                                                │
│  ┌───────────────────────────┐                                │
│  │ ModelSpecs (librechat.    │  ← Curated model picker UI     │
│  │ yaml)                     │    All 5 agents listed         │
│  └───────────────────────────┘                                │
└───────────────────────────────────────────────────────────────┘

Components

1. Master Agent

The single agent edited manually via the Agent Builder UI. It is also a fully functional, usable agent — users pick it from the model picker and chat with it directly.

PropertyValue
NameUvilo Agent GLM 5 Turbo
Agent IDagent_s5VyS1DBdUsGcsRxaw8x3
ProviderOpenRouter
Modelz-ai/glm-5-turbo

Contains:

  • System instructions — the full Uvilo assistant prompt
  • MCP server bindings — all configured servers
  • Deferred tool configuration — which tools load eagerly vs. on demand
  • Capabilities — Code Interpreter, File Search, Actions, Artifacts
  • Agent-level settings — temperature, max tokens, etc.

2. Variant Config File

A YAML file defining the master agent and all model variants. Lives in the repo at Forge/Configs/agent-sync.yaml.

# Forge/Configs/agent-sync.yaml
master_agent_name: "Uvilo Agent GLM 5 Turbo"

variants:
  - name: "Uvilo Agent GLM 5 Turbo"
    id: "agent_s5VyS1DBdUsGcsRxaw8x3"
    provider: "OpenRouter"
    model: "z-ai/glm-5-turbo"
  - name: "Uvilo Agent Opus 4.6"
    id: "agent_fJDpWR5hjKH0CBLav1YrC"
    provider: "anthropic"
    model: "claude-opus-4-6"
  - name: "Uvilo Agent Sonnet 4.6"
    id: "agent_zU45aNu760dOxWiG3HOJ_"
    provider: "anthropic"
    model: "claude-sonnet-4-6"
  - name: "Uvilo Agent GPT 5.1"
    id: "agent_rIUhG9GzxyXZg9bj7TDaN"
    provider: "openAI"
    model: "gpt-5.1"
  - name: "Uvilo Agent GPT 5.4"
    id: "agent_7nCIWSbZtMz94BOH5bOvt"
    provider: "openAI"
    model: "gpt-5.4"

Each variant has an id field:

  • Master agent: ID is known and hardcoded (agent_s5VyS1DBdUsGcsRxaw8x3). This entry is a no-op during sync (it’s the source, not a target).
  • Existing variants: IDs are populated from the first schema discovery run. The script looks up agents by id directly for precise updates.

Why ID-based lookup matters: Using _id directly (instead of finding by name) guarantees the script updates the exact right agent document. Name-only lookup is fragile — if someone renames an agent or creates a new one with the same name, the script could update the wrong document and break conversation links.

Adding a new model variant = add an entry with id: null, run /update-agents, paste the reported ID into the config, then update librechat.yaml ModelSpecs.

3. Sync Script (update-agents.ts)

A Python script that:

  1. Reads agent-sync.yaml for variant definitions
  2. Connects to MongoDB via MONGODB_URI environment variable
  3. Finds the master agent document by name
  4. For each variant (except the master itself):
    • If id is set: looks up the agent directly by _id for a precise update
    • If id is null: searches for an existing agent by name, or creates a new one
    • If found: updates the agent document in-place using $set on _id, preserving all conversation references
    • If not found: inserts a new agent document (cloned from master with model/provider overridden)
  5. Outputs a summary: which agents were created, updated, or skipped — and the ID of any newly created agents
  6. Generates ModelSpecs YAML entries for all variants (writes to stdout)
  7. If any new agent IDs were reported, prompts the user to update agent-sync.yaml with them before the next run

Critical: the script NEVER deletes agents and NEVER creates a new agent when one with that name already exists. Existing agents are always updated in-place to preserve conversation history.

Synced Fields

Copied from master to each variant on every sync:

FieldBehavior
nameSet from variant config (not copied from master)
modelSet from variant config (not copied from master)
providerSet from variant config (not copied from master)
instructionsCopied from master
toolsCopied from master (flat list of 378 tool ID strings)
model_parametersCopied from master (nested dict: temperature, max_tokens, top_p, etc.)
tool_optionsCopied from master (per-tool deferred loading config, 334 entries)
mcpServerNamesCopied from master (18 MCP server names)
artifactsCopied from master ("default")
descriptionCopied from master
categoryCopied from master ("general")
end_after_toolsCopied from master
hide_sequential_outputsCopied from master
is_promotedCopied from master
support_contactCopied from master
actionsCopied from master (empty array)
agent_idsCopied from master (empty array)
edgesCopied from master (empty array)
conversation_startersCopied from master (empty array)
tool_kwargsCopied from master (empty array)
projectIdsCopied from master (empty array)

Excluded Fields

Never overwritten on existing variants:

FieldReason
_idUnique identifier (ObjectId) — preserved to maintain conversation links
idAgent ID string — preserved to maintain conversation links
conversationsConversation history belongs to each variant
createdAtOriginal creation timestamp
updatedAtSet automatically by MongoDB
authorOwner — preserved
versionsVersion history — unique per agent
__vMongoose version key — preserved

Provider → Endpoint Mapping

The script maps provider names to LibreChat endpoint identifiers:

ProviderEndpoint
anthropicanthropic
openAIopenAI
OpenRouterOpenRouter
openrouteropenrouter
googlegoogle

4. MongoDB Access

  • Connection: via MONGO_URI environment variable (set on Railway service env)
  • Connection string: mongodb://mongo:<password>@mongodb.railway.internal:27017
  • Database: test
  • Collection: agents
  • Library: pymongo (installed via uv pip install pymongo)
  • Operations: find_one (lookup by name or id), update_one with $set (in-place update), insert_one (new agent)

5. ModelSpecs Configuration

Added to librechat.yaml to present all variant agents as a clean curated model picker. Each agent gets a ModelSpecs entry with its agent ID.

modelSpecs:
  enforce: false
  prioritize: true
  list:
    - name: "Uvilo Agent GLM 5 Turbo"
      label: "GLM 5 Turbo"
      endpoint: "agents"
      agent_id: "agent_s5VyS1DBdUsGcsRxaw8x3"
      preset:
        default: true
    - name: "Uvilo Agent Opus 4.6"
      label: "Opus 4.6"
      endpoint: "agents"
      agent_id: "<id from script output>"
      preset:
        default: true
    - name: "Uvilo Agent Sonnet 4.6"
      label: "Sonnet 4.6"
      endpoint: "agents"
      agent_id: "<id from script output>"
      preset:
        default: true
    - name: "Uvilo Agent GPT 5.1"
      label: "GPT 5.1"
      endpoint: "agents"
      agent_id: "<id from script output>"
      preset:
        default: true
    - name: "Uvilo Agent GPT 5.4"
      label: "GPT 5.4"
      endpoint: "agents"
      agent_id: "<id from script output>"
      preset:
        default: true

Agent IDs for non-master variants are populated after the first script run. The script outputs a ready-to-paste ModelSpecs snippet.

6. /update-agents Command

Registered in instructions.md as a command the assistant can execute:

  • Trigger: User says /update-agents or assistant runs it after editing the master agent
  • Execution: run("npx tsx /workspace/erik/uvilo-os/Forge/Skills/Update_Agents/scripts/update-agents.ts")
  • Output: Summary of what was created/updated/skipped + ModelSpecs snippet if agent IDs changed
  • Post-run: If ModelSpecs need updating, the assistant copies the snippet to librechat.yaml and reminds the user to /deploy-config + /redeploy

Data Flow

User edits Master Agent in Agent Builder UI


User runs /update-agents


Script reads agent-sync.yaml


Script connects to MongoDB via MONGODB_URI


Script reads master agent document by name
  └── verify master exists, capture its _id


For each non-master variant in config:
  ├── If variant.id is set:
  │   ├── find_one({ _id: variant.id })
  │   ├── If found → update_one({ _id }, { $set: synced_fields })
  │   └── If NOT found → Error: "Agent {variant.id} not found. Was it deleted?"
  └── If variant.id is null:
      ├── find_one({ name: variant.name })
      ├── If found → update_one({ _id }, { $set: synced_fields }), report ID
      └── If missing → insert_one(cloned_doc), report new ID


Output results summary
  └── Output ModelSpecs YAML snippet (for librechat.yaml)


Assistant updates librechat.yaml if ModelSpecs changed


User runs /deploy-config + /redeploy

File Structure

Forge/
├── Configs/
│   ├── agent-sync.yaml          # Variant configuration (version-controlled)
│   └── librechat.yaml           # Updated with ModelSpecs entries
├── Scripts/
│   └── update-agents.ts         # Sync script (version-controlled)
└── FORGE.md                     # Agent instructions (inlined into agents)

Implementation Steps

Phase 1: Schema Discovery

  • 1.1 Connect to MongoDB and inspect the master agent document (agent_s5VyS1DBdUsGcsRxaw8x3)
  • 1.2 Document all fields present in the agent schema
  • 1.3 Confirm field names for synced fields (instructions, tools, capabilities, etc.)
  • 1.4 Confirm provider → endpoint mapping from the master agent’s document
  • 1.5 Identify any additional fields not in the current synced/excluded tables
  • 1.6 Update this spec’s field tables with confirmed schema

Confirmed schema (Phase 1 results):

  • Env var: MONGO_URI (not MONGODB_URI)
  • Database: test (not librechat)
  • Connection: mongodb.railway.internal:27017 (internal Railway network)
  • Master agent provider: OpenRouter (not z-ai)
  • Master agent model: z-ai/glm-5-turbo
  • Model parameters nested in model_parameters dict (not top-level fields)
  • tool_options (not deferredTools) holds per-tool deferred loading config
  • mcpServerNames tracks MCP server bindings (18 servers)
  • tools is a flat list of 378 tool ID strings
  • artifacts field: "default"
  • versions is a list of version history entries
  • Empty arrays: actions, agent_ids, edges, conversation_starters, tool_kwargs, projectIds
  • Agent id field (string, e.g. agent_s5VyS1...) is separate from _id (ObjectId)

Phase 2: Script Development

  • 2.1 Create agent-sync.yaml with the 5 variant entries
  • 2.2 Build update-agents.ts:
    • MongoDB connection via MONGO_URI
    • Master agent lookup by name (with ID verification)
    • Variant find-or-create logic (find by name, update in-place, or insert)
    • Field cloning with model/provider/endpoint override
    • Provider → endpoint mapping
    • ModelSpecs YAML snippet generation (with all agent IDs)
    • Result reporting (created/updated/skipped counts)
  • 2.3 Test: run script, verify GLM 5 Turbo variant is a no-op (already is master)
  • 2.4 Test: verify one non-master variant is updated in-place (check _id preserved)
  • 2.5 Test: re-run script to verify idempotency (no changes on second run)
  • [BLOCKED] 2.6 Test: add a new variant to config, run script, verify it’s created (requires creating a throwaway agent in production DB)
  • 2.7 Test: verify ModelSpecs snippet output matches expected format

Phase 3: Integration

  • 3.1 Register /update-agents command in instructions.md
  • 3.2 Run script to get all agent IDs
  • 3.3 Populate ModelSpecs in librechat.yaml with actual agent IDs
  • 3.4 Deploy config and redeploy LibreChat
  • 3.5 Verify: all 5 agents appear in the model picker via ModelSpecs
  • 3.6 Verify: each agent has the correct model and all tools are available
  • 3.7 Verify: existing conversations are still accessible under their agents

Phase 4: Documentation

  • 4.1 Update Knowledge index with agent management notes
  • 4.2 Add operational lesson: “To add a new model, edit agent-sync.yaml, run /update-agents, update ModelSpecs in librechat.yaml, then /deploy-config + /redeploy”
  • 4.3 Mark spec as status: approved

Error Handling

ScenarioBehavior
MONGO_URI not setError: “MONGO_URI environment variable not set.”
MongoDB connection failureError: report connection details, suggest checking env var
Master agent not foundError: “Master agent ‘Uvilo Agent GLM 5 Turbo’ not found in MongoDB.”
Master agent ID mismatchWarning: “Master agent found but ID differs from expected agent_s5VyS1DBdUsGcsRxaw8x3. Using found ID.”
Variant config has unknown providerWarning: skip that variant, continue with others
Variant ID set but agent not foundError: “Agent {id} not found. Was it deleted?” — stops processing that variant
Variant ID is null, no agent by nameInfo: create new agent, report its ID for config update
Variant ID is null, agent found by nameInfo: update in-place, report ID for config update
Partial failure (some variants fail)Report which succeeded and which failed; don’t roll back successes
Script run with no changesInfo: “All variants are up to date.”

Safety Properties

  • Idempotent: Running the script N times produces the same result as running it once
  • Non-destructive: Existing agents are updated in-place; _id and conversations are never touched
  • Never deletes: The script has no delete logic — agents are only created or updated
  • Atomic per-variant: Each variant update is a single MongoDB $set operation
  • Conversation-preserving: Updating an agent in-place keeps all existing conversations linked
  • No LibreChat source changes: External script accessing the database directly

Prerequisites

Before implementation begins:

  • MONGO_URI environment variable set on Railway (contains the full MongoDB connection string for the LibreChat database)
  • pymongo available on the Railway volume (installed via uv pip install pymongo)
  • Master agent Uvilo Agent GLM 5 Turbo exists and is fully configured with all tools
  • All existing variant agents exist in MongoDB (will be found by name and updated in-place)