# Website Module — API Specification

## Introduction

The Codomyrmex Website module exposes a REST API via `WebsiteServer` (Python `http.server`). All endpoints return JSON. The server serves both static HTML pages (generated by `WebsiteGenerator`) and dynamic API endpoints backed by `DataProvider`.

Base URL: `http://localhost:{port}` (default port 8787)

---

## System Status

### GET `/api/status`

Quick system summary — module count, agent count, version, last build.

- **Response (200)**:
    ```json
    {
      "status": "Operational",
      "version": "0.1.0",
      "environment": "Development",
      "module_count": 42,
      "agent_count": 8,
      "last_build": "2026-02-09 10:30:00 -0800"
    }
    ```
- **Error (500)**: Data provider missing.

### GET `/api/health`

Comprehensive health — uptime, Python info, git info, module coverage stats, architecture layers.

- **Response (200)**:
    ```json
    {
      "uptime": "2h 15m 30s",
      "uptime_seconds": 8130,
      "python": {
        "version": "3.13.11",
        "executable": "/path/to/python",
        "platform": "macOS-15.3-arm64"
      },
      "git": {
        "branch": "main",
        "last_commit": "abc1234 fix bug (2 hours ago)",
        "commit_count": "150",
        "dirty_files": 5,
        "status": "5 changed"
      },
      "modules": {
        "total": 42,
        "with_tests": 20,
        "with_api_spec": 15,
        "with_mcp_spec": 10,
        "test_coverage_pct": 47.6,
        "api_spec_pct": 35.7,
        "mcp_spec_pct": 23.8
      },
      "architecture_layers": [
        {"name": "Foundation", "modules": ["logging_monitoring", "environment_setup"], "color": "#10b981"},
        {"name": "Core", "modules": ["agents", "coding"], "color": "#3b82f6"}
      ]
    }
    ```

---

## Module & Agent Discovery

### GET `/api/modules`

List all Codomyrmex modules (packages under `src/codomyrmex/`).

- **Response (200)**: JSON array of module objects.
    ```json
    [
      {
        "name": "coding",
        "status": "Active",
        "path": "src/codomyrmex/coding",
        "description": "Code editing module.",
        "submodules": []
      }
    ]
    ```

### GET `/api/modules/{name}`

Get enriched detail for a single module.

- **Parameters**:
    - `name` (string, path): Module name (e.g., `coding`).
- **Response (200)**:
    ```json
    {
      "name": "coding",
      "status": "Active",
      "path": "src/codomyrmex/coding",
      "description": "Code editing module.",
      "submodules": [],
      "has_tests": true,
      "has_api_spec": true,
      "has_mcp_spec": false,
      "has_readme": true,
      "python_file_count": 5
    }
    ```
- **Error (404)**: `{"error": "Module 'name' not found"}`

### GET `/api/agents`

List actual AI agent integrations from `src/codomyrmex/agents/`.

- **Response (200)**: JSON array of agent objects.
    ```json
    [
      {
        "name": "claude",
        "status": "Available",
        "path": "src/codomyrmex/agents/claude",
        "description": "Claude API integration.",
        "type": "API Integration"
      }
    ]
    ```

---

## Script Execution

### GET `/api/scripts`

List available scripts from the `scripts/` directory.

- **Response (200)**:
    ```json
    [
      {
        "name": "deploy.py",
        "title": "Deploy application",
        "path": "deploy.py",
        "full_path": "/abs/path/to/scripts/deploy.py",
        "description": "Deploy application."
      }
    ]
    ```

### POST `/api/execute`

Execute a script from the `scripts/` directory.

- **Request Body**:
    ```json
    {
      "script": "deploy.py",
      "args": ["--env", "staging"]
    }
    ```
- **Response (200)**:
    ```json
    {
      "success": true,
      "stdout": "Deployed successfully.",
      "stderr": "",
      "returncode": 0
    }
    ```
- **Error (400)**: Script name required.
- **Error (403)**: Invalid script path (traversal attempt).
- **Error (504)**: Script timed out (300s limit).

### POST `/api/tests`

Run pytest for a specific module or all modules.

- **Request Body**:
    ```json
    {
      "module": "website"
    }
    ```
    Omit `module` to run all tests.
- **Response (200)**:
    ```json
    {
      "passed": 92,
      "failed": 0,
      "skipped": 0,
      "errors": 0,
      "total": 92,
      "success": true,
      "returncode": 0,
      "output": "92 passed in 20.69s",
      "module": "website"
    }
    ```

---

## Configuration

### GET `/api/config`

List all configuration files found in the project root.

- **Response (200)**:
    ```json
    [
      {"name": "pyproject.toml", "path": "pyproject.toml", "type": "toml"},
      {"name": "config.yaml", "path": "config.yaml", "type": "yaml"}
    ]
    ```

### GET `/api/config/{filename}`

Read content of a specific configuration file.

- **Parameters**:
    - `filename` (string, path): File path relative to project root.
- **Response (200)**: `{"content": "file contents..."}`
- **Error (403)**: Path traversal or absolute path rejected.
- **Error (404)**: File not found.

### POST `/api/config/{filename}`

Save content to a configuration file.

- **Request Body**:
    ```json
    {
      "content": "new file contents...",
      "filename": "pyproject.toml"
    }
    ```
- **Response (200)**: `{"success": true, "filename": "pyproject.toml"}`
- **Error (400)**: Missing filename or content.
- **Error (403)**: Path traversal rejected.

---

## Documentation

### GET `/api/docs`

Get the documentation file tree (all `.md` files under `docs/` and `src/`).

- **Response (200)**:
    ```json
    {
      "name": "Documentation",
      "children": [
        {
          "name": "docs",
          "children": [
            {"name": "README.md", "path": "docs/README.md", "type": "file"}
          ]
        },
        {
          "name": "Modules",
          "children": [
            {"name": "codomyrmex/coding", "path": "src/codomyrmex/coding/README.md", "type": "file"}
          ]
        }
      ]
    }
    ```

### GET `/api/docs/{path}`

Read content of a specific documentation file.

- **Parameters**:
    - `path` (string, path): File path relative to project root. Must end in `.md`.
- **Response (200)**: `{"content": "# Markdown content..."}`
- **Error (403)**: Path traversal, absolute path, or non-`.md` file rejected.
- **Error (404)**: File not found.

---

## CI/CD Pipelines

### GET `/api/pipelines`

List CI/CD workflow definitions from `.github/workflows/*.yml`.

- **Response (200)**:
    ```json
    [
      {
        "id": "wf-0000",
        "name": "Continuous Integration",
        "status": "defined",
        "file": ".github/workflows/ci.yml",
        "triggers": ["push", "pull_request", "workflow_dispatch"],
        "stages": [
          {"name": "lint-and-format", "status": "defined"},
          {"name": "test", "status": "defined"}
        ]
      }
    ]
    ```

---

## PAI Awareness

### GET `/api/awareness`

Aggregated PAI ecosystem data — missions, projects, TELOS profile, memory system, metrics, and a Mermaid.js dependency graph.

- **Response (200)**:
    ```json
    {
      "missions": [
        {
          "id": "m1",
          "title": "My Mission",
          "status": "active",
          "priority": "HIGH",
          "description": "Mission description",
          "success_criteria": [],
          "linked_projects": ["p1"],
          "completion_percentage": 75,
          "recent_activity": []
        }
      ],
      "projects": [
        {
          "id": "p1",
          "title": "My Project",
          "status": "in_progress",
          "goal": "Build something",
          "priority": "HIGH",
          "parent_mission": "m1",
          "tags": ["python"],
          "completion_percentage": 50,
          "task_counts": {"completed": 5, "total": 10},
          "recent_activity": []
        }
      ],
      "telos": [
        {"name": "goals", "filename": "goals.md", "size_bytes": 1024, "preview": "# My Goals..."}
      ],
      "memory": {
        "directories": [
          {"name": "WORK", "file_count": 15, "subdir_count": 3}
        ],
        "total_files": 42,
        "work_sessions_count": 3
      },
      "metrics": {
        "mission_count": 1,
        "project_count": 1,
        "total_tasks": 10,
        "completed_tasks": 5,
        "telos_files": 1,
        "overall_completion": 50.0
      },
      "mermaid_graph": "graph TD\n    M_m1[\"My Mission\"]\n    M_m1 --> P_p1\n    P_p1[\"My Project\"]"
    }
    ```
- **Error (500)**: Data provider missing.

### POST `/api/awareness/summary`

Generate an Ollama AI summary of the current PAI ecosystem state.

- **Request Body**:
    ```json
    {
      "model": "llama3"
    }
    ```
- **Response (200)**:
    ```json
    {
      "summary": "Overall assessment: The ecosystem is healthy...",
      "model": "llama3",
      "success": true
    }
    ```
- **Error (400)**: No content provided.
- **Error (502)**: Ollama returned an error.
- **Error (503)**: Ollama service not reachable.
- **Error (504)**: Ollama request timed out.

---

## Chat

### POST `/api/chat`

Proxy chat messages to a local Ollama LLM instance.

- **Request Body**:
    ```json
    {
      "message": "Hello, explain this code.",
      "model": "llama3",
      "messages": [{"role": "user", "content": "Hello"}]
    }
    ```
- **Response (200)**:
    ```json
    {
      "response": "This code does...",
      "model": "llama3",
      "success": true
    }
    ```
- **Error (502)**: Ollama returned an error.
- **Error (503)**: Ollama service not reachable.
- **Error (504)**: Ollama request timed out.

---

## System Refresh

### POST `/api/refresh`

Refresh and return all system data in one call.

- **Response (200)**:
    ```json
    {
      "system": {"status": "Operational", "...": "..."},
      "modules": [{"name": "coding", "...": "..."}],
      "agents": [{"name": "claude", "...": "..."}],
      "scripts": [{"name": "deploy.py", "...": "..."}]
    }
    ```

---

## Data Models

### Module
- `name` (string): Module directory name.
- `status` (string): Always `"Active"`.
- `path` (string): Relative path from project root.
- `description` (string): From `__init__.py` docstring or README.
- `submodules` (array): Nested module objects.

### ModuleDetail (extends Module)
- `has_tests` (boolean): Whether test directory exists.
- `has_api_spec` (boolean): Whether `API_SPECIFICATION.md` exists.
- `has_mcp_spec` (boolean): Whether `MCP_TOOL_SPECIFICATION.md` exists.
- `has_readme` (boolean): Whether `README.md` exists.
- `python_file_count` (integer): Number of `.py` files.

### Agent
- `name` (string): Agent directory name.
- `status` (string): Always `"Available"`.
- `path` (string): Relative path.
- `description` (string): From docstring or README.
- `type` (string): One of `"CLI Integration"`, `"API Integration"`, `"Framework"`, `"Agent"`.

### Pipeline
- `id` (string): Auto-generated ID (`wf-NNNN`).
- `name` (string): From workflow YAML `name` field.
- `status` (string): Always `"defined"` (static scan).
- `file` (string): Relative path to workflow YAML.
- `triggers` (array of strings): Event triggers (push, pull_request, etc.).
- `stages` (array): Job objects with `name` and `status`.

### Script
- `name` (string): Relative path within `scripts/`.
- `title` (string): Extracted from docstring.
- `path` (string): Relative path.
- `full_path` (string): Absolute path.
- `description` (string): Full docstring.

---

## Python Class API

The website module exports three classes that can be used directly from Python.

### Class: `WebsiteGenerator`

Generates static HTML from Jinja2 templates and system data.

```python
class WebsiteGenerator:
    def __init__(self, output_dir: str, root_dir: str | None = None): ...
    def generate(self) -> None: ...
```

**Constructor Parameters:**
- `output_dir` (str): Directory where static site files will be written. Existing contents are replaced on each generation.
- `root_dir` (str | None, optional): Project root directory. Default: auto-detected by navigating four levels up from `generator.py`.

**`generate()`**: Runs the full generation pipeline:
1. Clears and recreates the output directory.
2. Collects system data via an internal `DataProvider`.
3. Renders all HTML pages (`index.html`, `health.html`, `modules.html`, `scripts.html`, `chat.html`, `agents.html`, `config.html`, `docs.html`, `pipelines.html`).
4. Copies static assets (CSS, JS) to the output directory.

### Class: `DataProvider`

Aggregates data from the file system, git, and CI/CD workflows.

```python
class DataProvider:
    def __init__(self, root_dir: Path): ...
```

**Constructor Parameters:**
- `root_dir` (Path): Path to the project root directory.

**Key Methods:**

| Method | Returns | Description |
|--------|---------|-------------|
| `get_system_summary()` | `dict[str, Any]` | Status, version, module/agent counts, last build timestamp |
| `get_modules()` | `list[dict[str, Any]]` | All packages under `src/codomyrmex/` with status and description |
| `get_module_detail(name: str)` | `dict[str, Any] \| None` | Enriched detail for a single module (tests, specs, file count) |
| `get_actual_agents()` | `list[dict[str, Any]]` | AI agent integrations from `src/codomyrmex/agents/` |
| `get_available_scripts()` | `list[dict[str, Any]]` | Python scripts found recursively under `scripts/` |
| `get_config_files()` | `list[dict[str, str]]` | Configuration files in the project root and `config/` directory |
| `get_config_content(filename: str)` | `str` | Content of a configuration file (path-traversal protected) |
| `save_config_content(filename: str, content: str)` | `None` | Write content to an existing configuration file |
| `get_doc_tree()` | `dict[str, Any]` | Tree of `.md` documentation files under `docs/` and `src/` |
| `get_doc_content(doc_path: str)` | `str` | Content of a documentation file (`.md` only, traversal protected) |
| `get_pipeline_status()` | `list[dict[str, Any]]` | CI/CD workflow definitions from `.github/workflows/*.yml` |
| `get_health_status()` | `dict[str, Any]` | Comprehensive health: uptime, python, git, module coverage, architecture layers |
| `run_tests(module: str \| None = None)` | `dict[str, Any]` | Run pytest and return structured results (passed/failed/skipped/errors) |
| `get_pai_missions()` | `list[dict[str, Any]]` | PAI missions from `~/.claude/MEMORY/STATE/missions/` |
| `get_pai_projects()` | `list[dict[str, Any]]` | PAI projects from `~/.claude/MEMORY/STATE/projects/` |
| `get_pai_tasks(project_id: str)` | `dict[str, Any]` | Parse TASKS.md for a specific project (path-traversal protected) |
| `get_pai_telos()` | `list[dict[str, Any]]` | TELOS life profile files from `~/.claude/USER/TELOS/` |
| `get_pai_memory_overview()` | `dict[str, Any]` | Memory directory stats (file counts, subdirectory counts) |
| `get_pai_awareness_data()` | `dict[str, Any]` | Aggregated PAI ecosystem data with metrics and Mermaid graph |

### Class: `WebsiteServer`

HTTP request handler composed from `APIHandler`, `HealthHandler`, `ProxyHandler`, and `http.server.SimpleHTTPRequestHandler`. Serves static files and handles API endpoints; handler mixins declare type-only host contracts so they can be checked independently.

```python
class WebsiteServer(APIHandler, HealthHandler, ProxyHandler, http.server.SimpleHTTPRequestHandler):
    root_dir: Path         # Class-level: project root directory
    data_provider: DataProvider | None  # Class-level: data provider instance
```

Set `root_dir` and `data_provider` on the class before starting the server. Use with `socketserver.TCPServer`:

```python
import socketserver
from codomyrmex.website import WebsiteServer, DataProvider

WebsiteServer.root_dir = Path("/path/to/project")
WebsiteServer.data_provider = DataProvider(WebsiteServer.root_dir)

with socketserver.TCPServer(("", 8787), WebsiteServer) as httpd:
    httpd.serve_forever()
```

**Security Features:**
- Origin validation via `_ALLOWED_ORIGINS` (defaults to `http://localhost:8787` and `http://127.0.0.1:8787`).
- Path traversal protection on script execution, config access, and documentation reads.
- Script execution restricted to the `scripts/` directory with a 300-second timeout.

---

## Authentication & Authorization

No authentication required. The server is designed for local development use only. POST endpoints validate the `Origin`/`Referer` header against `_ALLOWED_ORIGINS`.

## Rate Limiting

The `/api/tests` endpoint enforces a single-concurrent-run lock. If a test run is already in progress, subsequent requests receive HTTP 429 with `{"error": "A test run is already in progress. Please wait."}`. All other endpoints have no rate limiting.

## Versioning

No API versioning. Single version served by `WebsiteServer`.

---

## Navigation Links

- **Parent**: [Website README](./README.md)
- **Module Index**: [All Modules](../../AGENTS.md)
- **Documentation**: [Reference Guides](../../../docs/README.md)
- **Home**: [Root README](../../../README.md)
