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

Uvilo OS Plan Infrastructure

Status: Partially implemented. The Railway + LibreChat + MCP setup is live. The uvilo-git-remote custom Python FastMCP server (push/pull/fetch) is not captured in the original plan below. For current operational procedures, see Uvilo OS Setup. Key deviation from plan: switched from @cyanheads/git-mcp-server (Node.js) to the official Python mcp-server-git due to an incompatibility with LibreChat’s MCP SDK.

Current Setup (Verified)

  • Project: uvilo-libre-chat on Railway
  • Services: LibreChat, MongoDB, Meilisearch, RAG API, VectorDB — all running successfully
  • Domain: librechat.uvilo.ai
  • Config: librechat.yaml at Forge/Configs/LibreChat_Service/librechat.yaml in the repo, read from the volume at runtime via CONFIG_PATH
  • Deployment: Railway template (Docker image, not a GitHub repo deploy)
  • MCP status: A placeholder my-remote-mcp SSE server is configured but failing (points to example.com)
  • Multi-user: Needed soon

Architecture

┌──────────────────────────────────────────────────────────────────┐
│  Railway Project: uvilo-libre-chat                               │
│                                                                  │
│  ┌──────────────┐    stdio    ┌──────────────────────────┐      │
│  │  LibreChat    │◄──────────►│ MCP Filesystem Server    │      │
│  │  (existing)   │            │ MCP Git Server            │      │
│  │              │            │ MCP Git-Remote Server      │      │
│  │              │            └──────────────┬─────────────┘      │
│  │              │                            │                   │
│  │              │  HTTP/MCP   ┌──────────────────────────┐      │
│  │              │◄───────────►│ Playwright MCP           │      │
│  │              │ (priv. net) │ (headless Chromium)       │      │
│  │              │             │ mcr.microsoft.com/        │      │
│  │              │             │   playwright/mcp          │      │
│  └──────────────┘             │ Port 8931                 │      │
│                               └──────────────────────────┘      │
│                                                                  │
│         ┌──────────────────────┐                                 │
│         │  Railway Volume       │                                 │
│         │  /workspace/          │                                 │
│         │  ├── erik/            │  per-user working dirs          │
│         │  │   └── uvilo-os/   │◄──── git clone at startup       │
│         │  ├── sara/            │  (future users)                 │
│         │  │   └── uvilo-os/   │                                 │
│         │  └── ...              │                                 │
│         └──────────────────────┘                                 │
└──────────────────────────────────────────────────────────────────┘

Key Constraint: Template Deployment

Since LibreChat was deployed via Railway template, we’re working with a pre-built Docker image — not a GitHub repo we control. This means:

  1. We cannot modify the Dockerfile to add git, python, or custom startup scripts directly
  2. We CAN customize the start command in Railway’s service settings
  3. We CAN mount a volume to the service
  4. We CAN configure MCP servers via librechat.yaml on the volume (cloned from the repo)

The constraint is whether the LibreChat Docker image already has the tools we need:

  • npx (Node.js) — almost certainly yes (LibreChat is a Node.js app)
  • git — likely yes (many Docker images include it)
  • uvx / python — possibly not (needed for the Python-based git MCP server)

If python/uvx aren’t available, we use the Node.js-based @cyanheads/git-mcp-server instead (runs via npx).


Implementation Steps

Step 1: Verify container capabilities

Before adding anything, SSH into the running LibreChat container and check what tools are available:

railway shell --service LibreChat
# Then run:
which git && git --version
which npx && npx --version
which python3 && python3 --version
which uvx

This determines whether we can use the Python git MCP server or need the Node.js one.

Step 2: Create Railway volume

Attach a persistent volume to the LibreChat service:

  • Mount path: /workspace
  • This can be done via the Railway dashboard (recommended for first time) or CLI

Key facts about Railway volumes:

  • Data written at build time does NOT persist — must write at runtime
  • Volumes are not mounted during pre-deploy commands
  • Only one deployment can mount a volume at a time (brief downtime on redeploy)
  • Non-root Docker images may need RAILWAY_RUN_UID=0

Step 3: Set up git clone at startup

Add environment variables to the LibreChat service:

  • GITHUB_TOKEN — GitHub fine-grained PAT with Contents (read/write) for ErikDakoda/uvilo-os
  • GIT_AUTHOR_NAME=Erik Dakoda
  • GIT_AUTHOR_EMAIL=erikschannen@gmail.com
  • Update CONFIG_PATH to /workspace/erik/uvilo-os/Forge/Configs/LibreChat_Service/librechat.yaml

Override the LibreChat start command to clone/fetch the repo into a per-user directory:

bash -c '
REPO_DIR="/workspace/erik/uvilo-os"
mkdir -p /workspace/erik
if [ ! -d "$REPO_DIR/.git" ]; then
  git clone https://${GITHUB_TOKEN}@github.com/ErikDakoda/uvilo-os.git "$REPO_DIR"
  cd "$REPO_DIR" && git config user.name "$GIT_AUTHOR_NAME" && git config user.email "$GIT_AUTHOR_EMAIL"
else
  cd "$REPO_DIR" && git fetch --all && git pull --ff-only origin main 2>/dev/null || true
fi
exec npm start
'

The per-user directory structure (/workspace/erik/) means adding future users is just a matter of adding another clone block — no reorganization needed. The exec npm start (or whatever the default start command is) ensures LibreChat still starts normally after the git setup. We need to check the existing start command first.

Step 4: Update librechat.yaml with MCP servers

Update Forge/Configs/LibreChat_Service/librechat.yaml in the repo with working MCP servers. CONFIG_PATH will point to the volume copy at /workspace/erik/uvilo-os/Forge/Configs/LibreChat_Service/librechat.yaml:

# librechat.yaml
version: 1.2.1
cache: true

mcpServers:
  uvilo-filesystem:
    title: "Uvilo OS Files"
    description: "Read/write access to the Uvilo OS repository"
    command: npx
    args:
      - -y
      - "@modelcontextprotocol/server-filesystem"
      - /workspace/erik/uvilo-os
    timeout: 30000
    serverInstructions: |
      This provides access to the Uvilo OS repository — the single source of truth
      for Uvilo as a company. Use absolute paths starting with /workspace/erik/uvilo-os/.
      Key locations:
      - Architecture/ — product specs, quizzes, taxonomy, onboarding
      - Forge/ — AI agent infrastructure, skills, lessons
      - Content/, Design/, Finance/, Marketing/, Operations/, Planning/, Technology/
      File naming: Title_Case_With_Underscores for all files and folders.
      All markdown docs have YAML frontmatter (title, visibility, status, owner, tags).

  uvilo-git:
    title: "Uvilo OS Git"
    description: "Git operations for the Uvilo OS repository"
    command: uvx
    args:
      - mcp-server-git
      - --repository
      - /workspace/erik/uvilo-os
    timeout: 30000
    serverInstructions: |
      Git operations for the Uvilo OS repository.
      Branch naming: work/<user>/<topic>-<date> for working sessions.
      Always check status before committing.
      Never commit directly to main — always use branches and PRs.
      Commit messages should be descriptive and concise.

# If uvx is not available, replace uvilo-git with:
#  uvilo-git:
#    title: "Uvilo OS Git"
#    command: npx
#    args:
#      - -y
#      - "@cyanheads/git-mcp-server"
#    env:
#      GIT_DEFAULT_PATH: /workspace/erik/uvilo-os
#    timeout: 30000

endpoints:
  # ... keep existing endpoint config ...

Commit and push the change, then restart LibreChat. Since CONFIG_PATH points to the volume copy, the new config is picked up on restart.

Step 5: Validate end-to-end

Test the full workflow in LibreChat at librechat.uvilo.ai:

  1. Filesystem test: Select the uvilo-filesystem MCP, ask to list files in the repo root
  2. Read test: Ask to read Architecture/Uvilo_OS/Uvilo_OS_Spec.md
  3. Git status: Select uvilo-git MCP, ask for git status
  4. Branch + edit + commit:
    • Create branch work/erik/test-mcp-2026-03-07
    • Edit a test file via filesystem MCP
    • Stage, commit, and push via git MCP
  5. Verify on GitHub: Check that the branch appears at github.com/ErikDakoda/uvilo-os

Step 6: Multi-user expansion

The directory structure is already per-user from day one:

/workspace/
├── erik/
│   └── uvilo-os/    ← erik's git clone, on erik's branch
├── sara/            ← add future users here
│   └── uvilo-os/
└── ...

To add a new user:

  1. Add a clone block to the startup script for the new user directory
  2. Duplicate the MCP server entries in librechat.yaml with the new path
    • Or use {{LIBRECHAT_USER_ID}} in paths if LibreChat supports it in MCP args
  3. Restart LibreChat

LibreChat supports {{LIBRECHAT_USER_ID}} in MCP server headers and env vars. If it also supports it in args, the MCP config can be user-agnostic:

  uvilo-filesystem:
    command: npx
    args:
      - -y
      - "@modelcontextprotocol/server-filesystem"
      - /workspace/{{LIBRECHAT_USER_ID}}/uvilo-os

This needs testing — if it works, multi-user is nearly free.


Risks and Mitigations

RiskMitigation
Docker image lacks git/pythonCheck with railway shell; fall back to Node.js MCP servers
Volume not accessible to MCP child processesstdio processes inherit parent filesystem; test immediately
Start command override breaks LibreChatTest in a staging environment first; keep original command noted
Config lives in repo at Forge/Configs/LibreChat_Service/librechat.yaml, version-controlled and editable via MCP
MCP server errors spam logs (like current placeholder)Remove placeholder immediately; monitor logs after deploying real servers
Git conflicts in shared working directoryPer-user dirs from day one prevents this

Immediate Action: Fix the MCP Spam

The placeholder my-remote-mcp SSE server is generating error logs every 2 seconds. It will be removed when we update the config in the repo.


Playwright MCP — Browser Automation

A separate Railway service running the official Microsoft Playwright MCP Docker image provides headless Chromium browser capabilities to the AI assistant.

  • Service name: playwright-mcp
  • Image: mcr.microsoft.com/playwright/mcp
  • Custom Start Command: node cli.js --headless --browser chromium --no-sandbox --port 8931 --host 0.0.0.0 (overrides the image’s ENTRYPOINT in exec form)
  • Serverless: Enabled — sleeps after 10 min inactivity, wakes on private network traffic (~5–15s cold start)
  • Transport: streamable-http over Railway private network
  • Internal URL: http://playwright-mcp.railway.internal:8931/mcp
  • Memory: 512MB–1GB recommended
  • No public domain — internal only

LibreChat connects via mcpSettings.allowedDomains whitelist and type: streamable-http. See Playwright MCP Research for full evaluation.


TinaCMS — Deferred

TinaCMS adds significant complexity (separate Next.js app, content schema, database, auth) and is not on the critical path. The core editing workflow is fully covered by LibreChat + MCP servers. Revisit after Phases 1-2 are validated.


Estimated Timeline

StepEffortDependencies
1. Verify container capabilities10 minRailway shell access
2. Create volume5 minRailway Pro plan
3. Set up git clone at startup30 minGitHub PAT, start command
4. Update librechat.yaml30 minStep 1 results (choose git MCP server)
5. Validate end-to-end30 minSteps 1-4 complete
6. Multi-user expansion1-2 hoursTest {{LIBRECHAT_USER_ID}} in args

Total for working single-user setup: ~2 hours


Agentic Execution — Orchestrator

Overview

An external orchestrator script will chain LibreChat agent sessions to implement projects autonomously across multiple sessions. This is separate from the existing MCP infrastructure which provides per-session file and git access.

Architecture

The orchestrator is a Python script running as a separate Railway service (or cron job on the LibreChat service). It:

  1. Reads Project_Name_State.md files from projects in the repo
  2. Determines the next actionable task (unchecked or [STARTED])
  3. Calls LibreChat’s Agents API with the task prompt + session log context
  4. Monitors agent progress via streaming responses
  5. On completion/timeout, updates the State document and session_log.md
  6. Optionally starts the next session or waits for a schedule/trigger

LibreChat Agents API Setup

The Agents API is gated behind the remoteAgents interface configuration in librechat.yaml:

interface:
  remoteAgents:
    use: true
    create: true

Once enabled, users can generate API keys from the LibreChat UI. The orchestrator uses these keys to call the OpenAI-compatible chat completions endpoint or the Open Responses endpoint.

Orchestrator Invocation Example

from openai import OpenAI

client = OpenAI(
    base_url="https://librechat.uvilo.ai/api/agents/v1",
    api_key="YOUR_LIBRECHAT_API_KEY"
)

response = client.chat.completions.create(
    model="agent_uvilo_builder",  # LibreChat agent ID
    messages=[
        {"role": "user", "content": task_prompt}
    ],
    stream=True
)

Prerequisites

  • Enable remoteAgents in librechat.yaml
  • Create a LibreChat agent with Uvilo OS system prompt and MCP tools attached
  • Generate an API key from LibreChat UI
  • Deploy orchestrator script on Railway

LibreChat 2026 Roadmap Alignment

LibreChat’s Q2 2026 roadmap includes “agent workflows that run on a schedule and/or triggered by other agents, enabling automation and background processing.” When this ships, it may replace the external orchestrator with a native LibreChat feature.