Of course. Here is a single, detailed, and self-contained plan designed to be executed by an agentic LLM. The plan is structured with clear phases, steps, file paths, and the exact content for each file and command.

-----

### **Agentic LLM Execution Plan: Project "Streamline Gateway"**

**Persona:** You are an expert DevOps and Python developer. Your task is to construct a complete, containerized web application project from scratch based on the following plan. You will create a directory structure, write code and configuration files, and provide the final commands to build and run the project.

**Project Goal:** To create a single Docker container that hosts multiple independent Streamlit applications. Access to these applications will be managed by a FastAPI reverse proxy, which also serves a central navigation page. Project dependencies will be modularly defined in separate `pyproject.toml` files and installed into a unified environment using `uv` workspaces.

**Success Criteria:**

1.  All specified files and directories are created with the exact content provided.
2.  The Docker image builds successfully without errors.
3.  When the Docker container is run, it exposes a service on port 8000.
4.  Accessing `http://localhost:8000` in a web browser displays a navigation page with links to two apps.
5.  Accessing `http://localhost:8000/app1/` and `http://localhost:8000/app2/` successfully loads and runs the respective interactive Streamlit applications.
6.  The code adheres to modern Python standards, is fully strictly typed, and `ruff` tool is used for formatting and linting.
-----

### **Execution Plan**

#### **Phase 1: Project Scaffolding**

**Step 1. Create the application and proxy directories**

```bash
cd /multi-app-workspace
mkdir -p apps/app1
mkdir -p apps/app2
mkdir -p proxy
```

-----

#### **Phase 2: Application Code Development**

Create the Python source files for the proxy and the two Streamlit applications.

**Step 2.1: Create the FastAPI Proxy (`proxy/main.py`)**
Write the following content to `proxy/main.py`:

```python
import httpx
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, StreamingResponse
from starlette.websockets import WebSocket, WebSocketDisconnect

app = FastAPI()

APP_MAP = {
    "app1": "http://localhost:8501",
    "app2": "http://localhost:8502",
}

client = httpx.AsyncClient()

@app.get("/", response_class=HTMLResponse)
async def read_root():
    body = """
    <html><head><title>Streamline Gateway</title></head>
    <body><h1>Welcome to the Streamline Gateway!</h1><h2>Available Apps:</h2>
    <ul><li><a href="/app1/" target="_blank">🚀 App 1: Data Explorer</a></li>
    <li><a href="/app2/" target="_blank">🤖 App 2: Text Repeater</a></li></ul></body></html>
    """
    return HTMLResponse(content=body)

@app.websocket("/{app_name}/stream")
async def websocket_proxy(websocket: WebSocket, app_name: str):
    if app_name not in APP_MAP:
        await websocket.close(code=404); return

    target_url = f"{APP_MAP[app_name].replace('http', 'ws')}/stream"
    await websocket.accept()
    async with client.websocket(target_url) as remote_ws:
        try:
            while True:
                data = await websocket.receive_text()
                await remote_ws.send_text(data)
                response = await remote_ws.receive_text()
                await websocket.send_text(response)
        except WebSocketDisconnect:
            print(f"Client disconnected from {app_name}")
        except Exception as e:
            print(f"Error in WebSocket proxy for {app_name}: {e}")

@app.api_route("/{app_name}/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def http_proxy(request: Request, app_name: str, path: str):
    if app_name not in APP_MAP:
        return HTMLResponse(status_code=404, content="App not found")

    target_url = f"{APP_MAP[app_name]}/{path}"
    req = client.build_request(
        method=request.method, url=target_url,
        headers=request.headers, content=await request.body())
    resp = await client.send(req, stream=True)
    return StreamingResponse(
        resp.aiter_raw(), status_code=resp.status_code, headers=resp.headers)
```

**Step 2.2: Create Streamlit App 1 (`apps/app1/app1.py`)**
Write the following content to `apps/app1/app1.py`:

```python
import streamlit as st
import numpy as np

st.set_page_config(page_title="App 1: Data Explorer", layout="wide")
st.title("🚀 App 1: Data Explorer")
st.write("This is a simple app to generate and plot random data.")
num_points = st.slider("Select number of data points:", 50, 500, 100)
data = np.random.randn(num_points, 2)
st.scatter_chart(data)
```

**Step 2.3: Create Streamlit App 2 (`apps/app2/app2.py`)**
Write the following content to `apps/app2/app2.py`:

```python
import streamlit as st

st.set_page_config(page_title="App 2: Text Repeater", layout="wide")
st.title("🤖 App 2: Text Repeater")
st.write("Enter some text and see it repeated below.")
user_text = st.text_input("Your text here:", "Hello from Streamline Gateway!")
if user_text:
    st.markdown("---")
    st.markdown(f"**You wrote:** *{user_text}*")
```

-----

#### **Phase 3: Dependency and Workspace Configuration**

Define the dependencies for each component and configure the `uv` workspace.

**Step 3.1: Create `proxy/pyproject.toml`**

```toml
[project]
name = "proxy"
version = "0.1.0"
dependencies = [
    "fastapi",
    "uvicorn[standard]",
    "httpx",
]
```

**Step 3.2: Create `apps/app1/pyproject.toml`**

```toml
[project]
name = "app1"
version = "0.1.0"
dependencies = [
    "streamlit",
    "numpy",
]
```

**Step 3.3: Create `apps/app2/pyproject.toml`**

```toml
[project]
name = "app2"
version = "0.1.0"
dependencies = [
    "streamlit",
]
```

**Step 3.4: Create `uv.workspace.toml`**
Write the following content to `uv.workspace.toml` in the project root:

```toml
[workspace]
members = [
    "proxy",
    "apps/app1",
    "apps/app2"
]
```

-----

#### **Phase 4: Process Management and Containerization**

Create the startup script and the Dockerfile.

**Step 4.1: Create the Startup Script (`start.sh`)**
Write the following content to `start.sh` in the project root:

```bash
#!/bin/bash

# Start the FastAPI proxy
echo "Starting FastAPI proxy..."
uvicorn proxy.main:app --host 0.0.0.0 --port 8000 &

# Start Streamlit App 1
echo "Starting Streamlit app 1..."
streamlit run apps/app1/app1.py --server.port=8501 --server.headless=true --server.enableCORS=false &

# Start Streamlit App 2
echo "Starting Streamlit app 2..."
streamlit run apps/app2/app2.py --server.port=8502 --server.headless=true --server.enableCORS=false &

# Wait for any process to exit
wait -n

# Exit with status of process that exited first
exit $?
```

**Step 4.2: Create the Dockerfile**
Write the following content to `Dockerfile` in the project root:

```dockerfile
# Use an official Python runtime as a parent image
FROM python:3.11-slim

# Set the working directory
WORKDIR /app

# 1. Install uv in the global environment
RUN pip install uv

# 2. Create a virtual environment using uv
RUN uv venv

# 3. Add the virtual environment's bin to the PATH
# This allows running `uvicorn` and `streamlit` directly
ENV PATH="/app/.venv/bin:$PATH"

# 4. Copy only dependency definition files first to leverage Docker cache
COPY apps/app1/pyproject.toml apps/app1/
COPY apps/app2/pyproject.toml apps/app2/
COPY proxy/pyproject.toml proxy/
COPY uv.workspace.toml .

# 5. Install all dependencies from the workspace into the venv
# `uv pip sync` ensures the environment exactly matches the toml files
RUN uv pip sync --workspace

# 6. Copy the rest of the application source code
COPY apps/ /app/apps/
COPY proxy/ /app/proxy/
COPY start.sh .

# Make the start script executable
RUN chmod +x ./start.sh

# Expose the port the FastAPI app runs on
EXPOSE 8000

# Command to run the application
CMD ["./start.sh"]
```

-----

#### **Phase 5: Build and Deployment**

Provide the final shell commands to build and run the entire application.

**Step 5.1: Build the Docker Image**
Execute this command in the project root (`/multi-app-workspace`):

```bash
docker build -t streamline-gateway .
```

**Step 5.2: Run the Docker Container**
Execute this command to run the newly built image:

```bash
docker run -p 8000:8000 streamline-gateway
```

-----

#### **Phase 6: Verification Instructions**

Provide instructions for a human to verify the successful completion of the project.

1.  Open a web browser.
2.  Navigate to `http://localhost:8000`.
3.  **Expected Result:** You should see the "Welcome to the Streamline Gateway\!" page with two links.
4.  Click the "App 1: Data Explorer" link.
5.  **Expected Result:** A new tab should open to `http://localhost:8000/app1/` and display the interactive data explorer Streamlit app.
6.  Navigate back to the gateway and click the "App 2: Text Repeater" link.
7.  **Expected Result:** A new tab should open to `http://localhost:8000/app2/` and display the interactive text repeater Streamlit app.

-----

**End of Plan.**