Operator Architecture
Overview
The Knowledge Graph platform uses two main tools for installation and operation:
- install.sh - One-time bootstrapper that sets up the platform
- operator.sh - Thin shim that delegates to operator container
Architecture: Thin Shim + Container Delegation
Principle: Minimal host logic, delegate everything possible to operator container
install.sh (one-time bootstrap)
│
├─► Downloads: operator.sh, compose files, schema
├─► Generates: .env (secrets)
├─► Configures: SSL (certs, nginx config)
├─► Bootstraps: docker compose up postgres garage operator
├─► Delegates config to container
└─► Shows summary
operator.sh (thin shim on HOST, ~200 lines)
│
├─► HOST-ONLY: start_infra, stop, teardown, update, logs, restart, status
│
└─► DELEGATED TO CONTAINER (docker exec kg-operator ...):
├─► start → /workspace/operator/lib/start-platform.sh
├─► upgrade → /workspace/operator/lib/upgrade.sh
└─► admin, ai-provider, embedding, api-key → configure.py
kg-operator container (has ALL logic)
│
├─► docker.io CLI (controls sibling containers via socket)
├─► postgresql-client (psql for migrations)
├─► /workspace/operator/lib/*.sh scripts
└─► /workspace/operator/configure.py
Current Architecture (Legacy)
install.sh Responsibilities
| Step | Action | Runs On | Artifacts Created |
|---|---|---|---|
| 1. Prerequisites | Check OS, curl, ports | Host | - |
| 2. Docker | Install/verify Docker | Host | Docker engine |
| 3. Macvlan | Create/detect network | Host | Docker network |
| 4. Download files | Fetch compose files, operator scripts | Host | docker-compose*.yml, operator/lib/*.sh |
| 5. Secrets | Generate passwords, keys | Host | .env |
| 6. SSL | Obtain/generate certificates | Host | certs/, nginx.ssl.conf |
| 7. Start | Pull images, start containers | Host→Docker | Running containers |
| 8. Configure | Set admin password, OAuth, embeddings | Container (operator) | Database config |
operator.sh Command Matrix
| Command | Runs On | Uses | Description |
|---|---|---|---|
init |
Host | lib/guided-init.sh |
Interactive setup (dev mode) |
start |
Host | lib/start-infra.sh, lib/start-app.sh |
Start platform |
stop |
Host | lib/stop.sh |
Stop platform |
restart |
Host | stop + start | Restart platform |
upgrade |
Host | lib/upgrade.sh |
Pull images, migrate, restart |
update |
Host | docker compose pull | Pull images only |
status |
Host | docker compose ps | Show container status |
logs |
Host | docker compose logs | View logs |
shell |
Container | docker exec | Enter operator container |
teardown |
Host | lib/teardown.sh |
Remove platform |
recert |
Host | acme.sh | Renew SSL certificates |
admin |
Container | configure.py | Admin user management |
ai-provider |
Container | configure.py | Configure AI extraction |
embedding |
Container | configure.py | Configure embeddings |
api-key |
Container | configure.py | Manage API keys |
Execution Locations
┌─────────────────────────────────────────────────────────────────┐
│ HOST │
│ │
│ install.sh ─────────────────────────────────────────────────► │
│ │ │
│ ├─► Downloads: operator.sh, operator/lib/*.sh │
│ ├─► Creates: .env, docker-compose.ssl.yml, certs/ │
│ └─► Runs: docker compose up │
│ │
│ operator.sh ────────────────────────────────────────────────► │
│ │ │
│ ├─► Host scripts: start, stop, upgrade, logs, status │
│ │ Uses: operator/lib/*.sh (downloaded by install.sh) │
│ │ │
│ └─► Container exec: shell, admin, ai-provider, embedding │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ kg-operator CONTAINER │ │
│ │ │ │
│ │ configure.py ─── Direct database/API access │ │
│ │ /app/operator/lib/*.sh ─── Baked into image │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Issues with Current Architecture
1. Script Duplication
operator/lib/*.shexists in both:- Host filesystem (downloaded by install.sh)
- Operator container image (baked in at build)
- Must keep both in sync
2. Permission Problems
- install.sh downloads scripts via curl (no execute bit)
- Fixed by adding chmod, but fragile
3. Mixed Execution Model
- Some commands run on host, some in container
- Confusing mental model
- Host scripts need docker socket access
Proposed Architecture (Future)
Option A: Container-First
Move all operations into the operator container:
operator.sh (thin shim)
└─► ALL commands → docker exec kg-operator operator-cli <command>
kg-operator container:
├─► operator-cli start/stop/upgrade (controls sibling containers)
├─► operator-cli admin/ai-provider/embedding (database config)
└─► Mounts docker socket for container control
Pros: Single execution environment, simpler install.sh, no permission issues Cons: Requires docker socket mount, security considerations
Option B: Clear Host/Container Split
Make the split explicit and intentional:
operator.sh:
├─► Infrastructure commands (start/stop/upgrade) → Host scripts
└─► Configuration commands (admin/ai-provider) → Container exec
Host scripts bundled in operator.sh itself (no separate lib/ files)
Pros: No downloaded scripts, clear separation Cons: Large operator.sh, still mixed model
Option C: Install-time vs Runtime Split
install.sh:
└─► Full installation including first start
operator.sh:
└─► Runtime management only (all via container exec)
└─► For infrastructure changes, re-run install.sh with flags
Pros: Clean separation, operator.sh is trivial Cons: install.sh becomes the primary tool
Files Inventory
Downloaded by install.sh to Host
knowledge-graph/
├── .env # Secrets
├── .operator.conf # Configuration
├── docker-compose.yml # Base compose
├── docker-compose.prod.yml # Production overrides
├── docker-compose.ghcr.yml # GHCR image references
├── docker-compose.ssl.yml # SSL configuration
├── nginx.ssl.conf # Nginx HTTPS config
├── certs/ # SSL certificates
├── operator.sh # Management shim
├── operator/
│ ├── configure.py # Python config tool
│ ├── lib/
│ │ ├── common.sh
│ │ ├── start-infra.sh
│ │ ├── start-app.sh
│ │ ├── stop.sh
│ │ ├── upgrade.sh
│ │ └── teardown.sh
│ └── database/
│ ├── migrate-db.sh
│ └── backup-database.sh
└── schema/
└── 00_baseline.sql