From a4431277790193bd93b7fdc1c711415c825b2d2c Mon Sep 17 00:00:00 2001 From: Alex Blank Date: Sat, 16 May 2026 13:44:40 +0200 Subject: [PATCH] chore(openspec): archive completed OpenSpec changes - Archive config-secrets (FN-009) change - Archive deployment-config (FN-006) change - Archive runfusion-poc (FN-008) change --- .../changes/config-secrets/.openspec.yaml | 2 - openspec/changes/config-secrets/design.md | 63 ----------------- openspec/changes/config-secrets/proposal.md | 29 -------- .../specs/config-management/spec.md | 37 ---------- .../specs/runtime-injection/spec.md | 40 ----------- .../specs/secret-management/spec.md | 37 ---------- openspec/changes/config-secrets/tasks.md | 48 ------------- .../changes/deployment-config/.openspec.yaml | 2 - openspec/changes/deployment-config/design.md | 67 ------------------- .../changes/deployment-config/proposal.md | 31 --------- .../specs/portainer-deployment/spec.md | 22 ------ .../specs/production-compose-stack/spec.md | 28 -------- .../specs/subdomain-routing/spec.md | 23 ------- .../specs/traefik-label-generator/spec.md | 24 ------- openspec/changes/deployment-config/tasks.md | 44 ------------ openspec/changes/runfusion-poc/.openspec.yaml | 2 - openspec/changes/runfusion-poc/design.md | 65 ------------------ openspec/changes/runfusion-poc/proposal.md | 28 -------- .../specs/executable-environment/spec.md | 27 -------- .../specs/health-reporting/spec.md | 22 ------ .../specs/runfusion-manifest/spec.md | 15 ----- openspec/changes/runfusion-poc/tasks.md | 42 ------------ 22 files changed, 698 deletions(-) delete mode 100644 openspec/changes/config-secrets/.openspec.yaml delete mode 100644 openspec/changes/config-secrets/design.md delete mode 100644 openspec/changes/config-secrets/proposal.md delete mode 100644 openspec/changes/config-secrets/specs/config-management/spec.md delete mode 100644 openspec/changes/config-secrets/specs/runtime-injection/spec.md delete mode 100644 openspec/changes/config-secrets/specs/secret-management/spec.md delete mode 100644 openspec/changes/config-secrets/tasks.md delete mode 100644 openspec/changes/deployment-config/.openspec.yaml delete mode 100644 openspec/changes/deployment-config/design.md delete mode 100644 openspec/changes/deployment-config/proposal.md delete mode 100644 openspec/changes/deployment-config/specs/portainer-deployment/spec.md delete mode 100644 openspec/changes/deployment-config/specs/production-compose-stack/spec.md delete mode 100644 openspec/changes/deployment-config/specs/subdomain-routing/spec.md delete mode 100644 openspec/changes/deployment-config/specs/traefik-label-generator/spec.md delete mode 100644 openspec/changes/deployment-config/tasks.md delete mode 100644 openspec/changes/runfusion-poc/.openspec.yaml delete mode 100644 openspec/changes/runfusion-poc/design.md delete mode 100644 openspec/changes/runfusion-poc/proposal.md delete mode 100644 openspec/changes/runfusion-poc/specs/executable-environment/spec.md delete mode 100644 openspec/changes/runfusion-poc/specs/health-reporting/spec.md delete mode 100644 openspec/changes/runfusion-poc/specs/runfusion-manifest/spec.md delete mode 100644 openspec/changes/runfusion-poc/tasks.md diff --git a/openspec/changes/config-secrets/.openspec.yaml b/openspec/changes/config-secrets/.openspec.yaml deleted file mode 100644 index 66dd08a..0000000 --- a/openspec/changes/config-secrets/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-05-14 diff --git a/openspec/changes/config-secrets/design.md b/openspec/changes/config-secrets/design.md deleted file mode 100644 index 19bb157..0000000 --- a/openspec/changes/config-secrets/design.md +++ /dev/null @@ -1,63 +0,0 @@ -## Context - -The backend has Config and Secret models (FN-004) with scope fields, but no frontend UI or runtime injection. SSH keys already use Fernet encryption (FN-011), so the encryption pattern is established. This design completes the config/secrets lifecycle. - -Current state: -- Config model: key, value, scope (global/user/project/instance), scope_id -- Secret model: key, encrypted_value, scope, scope_id -- Fernet encryption utilities exist in app/encryption.py -- No UI for management -- No runtime injection into containers - -## Goals / Non-Goals - -**Goals:** -- Allow users to manage configs and secrets via UI -- Inject configs/secrets into tool containers at spawn time -- Support scope-based inheritance (instance overrides project overrides user overrides global) -- Maintain encryption for all secret values - -**Non-Goals:** -- Secret versioning or history -- Automatic secret rotation -- Integration with external secret managers (Vault, AWS Secrets Manager) -- Config/secrets for non-tool resources - -## Decisions - -**1. Mount configs as files, secrets as env vars** -- Rationale: Configs (JSON) are often files (e.g., settings.json). Secrets are typically env vars. -- Config mount: `/app/config/.json` -- Secret env: `=` - -**2. Scope resolution: closest match wins** -- Rationale: Instance-specific values should override project defaults -- Resolution order: instance → project → user → global - -**3. Secret values never sent to frontend decrypted** -- Rationale: Security. Frontend only sees masked values (e.g., `••••••`). -- Decryption happens only in backend during runtime injection - -**4. Config values are plaintext (not encrypted)** -- Rationale: Configs are not sensitive. Encrypting them adds complexity without security benefit. - -## Risks / Trade-offs - -**[Risk] Secret injection at spawn time could fail silently** -→ Mitigation: Validate all referenced secrets exist before spawning. Return error if missing. - -**[Risk] Config files in containers could be read by other processes** -→ Mitigation: Mount config files with restrictive permissions (0400). Run containers as non-root. - -**[Risk] Large configs could exceed container env var limits** -→ Mitigation: Document size limits. Consider config file mounting for large values. - -## Migration Plan - -No migration needed. This extends existing models. - -## Open Questions - -1. Should configs support JSON schema validation? -2. Do we need bulk import/export for configs/secrets? -3. Should secret keys be validated against a naming convention? diff --git a/openspec/changes/config-secrets/proposal.md b/openspec/changes/config-secrets/proposal.md deleted file mode 100644 index 8a9afe1..0000000 --- a/openspec/changes/config-secrets/proposal.md +++ /dev/null @@ -1,29 +0,0 @@ -## Why - -Tool instances need runtime configuration and secrets (API keys, database passwords, etc.). The backend has Config and Secret models (FN-004), but there's no UI for users to manage these values, and no runtime injection mechanism to pass them into spawned containers. - -## What Changes - -- **Config management UI**: Frontend pages for creating, updating, and deleting config values at global/user/project/instance scopes -- **Secret management UI**: Frontend pages for encrypted secret storage with masked value display -- **Runtime injection**: Backend service that mounts configs and secrets into tool containers at spawn time -- **Scope-based access control**: Configs/secrets respect scope hierarchy (global → user → project → instance) -- **Encryption verification**: Ensure Fernet encryption is properly applied to all secret values - -## Capabilities - -### New Capabilities -- `config-management`: CRUD operations for configuration values with scope support -- `secret-management`: Encrypted storage and retrieval of sensitive values -- `runtime-injection`: Mount configs and secrets into tool containers at spawn - -### Modified Capabilities -- None (extends existing Config/Secret models) - -## Impact - -- **apps/web/src/**: New config and secret management pages -- **apps/api/app/routers/configs.py**: Enhanced with scope filtering -- **apps/api/app/routers/secrets.py**: Enhanced with scope filtering -- **apps/api/app/services/**: New runtime injection service -- **apps/api/app/models/**: Potential Config/Secret model updates for scope validation diff --git a/openspec/changes/config-secrets/specs/config-management/spec.md b/openspec/changes/config-secrets/specs/config-management/spec.md deleted file mode 100644 index 6b05e64..0000000 --- a/openspec/changes/config-secrets/specs/config-management/spec.md +++ /dev/null @@ -1,37 +0,0 @@ -## ADDED Requirements - -### Requirement: User can create config values -The system SHALL allow users to create configuration values at various scopes. - -#### Scenario: Create project config -- **WHEN** the user navigates to project settings -- **AND** clicks "Add Config" -- **THEN** a form appears with key, value, and scope fields -- **AND** submitting creates a config at the selected scope - -#### Scenario: Config scope validation -- **WHEN** the user creates a config -- **THEN** the scope must be one of: global, user, project, instance -- **AND** the scope_id must match the selected scope type - -### Requirement: User can view and update configs -The system SHALL display configs with scope-based filtering. - -#### Scenario: List configs -- **WHEN** the user views configs for a project -- **THEN** all configs visible at project scope or above are displayed -- **AND** values are shown as formatted JSON - -#### Scenario: Update config -- **WHEN** the user edits a config value -- **THEN** the updated value is saved -- **AND** the change takes effect on next tool spawn - -### Requirement: User can delete configs -The system SHALL allow deletion of config values. - -#### Scenario: Delete config -- **WHEN** the user clicks delete on a config -- **THEN** a confirmation dialog appears -- **AND** confirming removes the config -- **AND** the config is no longer injected into containers diff --git a/openspec/changes/config-secrets/specs/runtime-injection/spec.md b/openspec/changes/config-secrets/specs/runtime-injection/spec.md deleted file mode 100644 index 7b2de18..0000000 --- a/openspec/changes/config-secrets/specs/runtime-injection/spec.md +++ /dev/null @@ -1,40 +0,0 @@ -## ADDED Requirements - -### Requirement: Configs are mounted into tool containers -The system SHALL mount configuration values as files into spawned tool containers. - -#### Scenario: Config file mount -- **WHEN** a tool instance is spawned -- **THEN** all applicable configs are written to /app/config/ -- **AND** each config is a separate JSON file named by key -- **AND** files have restrictive permissions (0400) - -#### Scenario: Config scope resolution -- **WHEN** configs are resolved for a tool instance -- **THEN** the system collects configs from all applicable scopes -- **AND** instance scope overrides project scope -- **AND** project scope overrides user scope -- **AND** user scope overrides global scope - -### Requirement: Secrets are injected as environment variables -The system SHALL inject secret values as environment variables into tool containers. - -#### Scenario: Secret env var injection -- **WHEN** a tool instance is spawned -- **THEN** all applicable secrets are decrypted -- **AND** injected as environment variables with uppercase keys -- **AND** the container process can access them - -#### Scenario: Secret scope resolution -- **WHEN** secrets are resolved for a tool instance -- **THEN** the same scope hierarchy applies as configs -- **AND** closest scope wins on key collision - -### Requirement: Missing secrets fail spawn -The system SHALL prevent spawning if referenced secrets are missing. - -#### Scenario: Validate secrets before spawn -- **WHEN** a spawn request references a secret by key -- **AND** the secret does not exist in any applicable scope -- **THEN** the spawn fails with a clear error message -- **AND** no container is created diff --git a/openspec/changes/config-secrets/specs/secret-management/spec.md b/openspec/changes/config-secrets/specs/secret-management/spec.md deleted file mode 100644 index f6dc3bf..0000000 --- a/openspec/changes/config-secrets/specs/secret-management/spec.md +++ /dev/null @@ -1,37 +0,0 @@ -## ADDED Requirements - -### Requirement: User can create secrets -The system SHALL allow users to store encrypted secret values. - -#### Scenario: Create secret -- **WHEN** the user navigates to project secrets -- **AND** clicks "Add Secret" -- **THEN** a form appears with key and value fields -- **AND** the value is encrypted with Fernet before storage -- **AND** the user sees a masked value (e.g., ••••••) after creation - -#### Scenario: Secret scope -- **WHEN** the user creates a secret -- **THEN** the scope can be user, project, or instance -- **AND** the secret is only visible within that scope hierarchy - -### Requirement: Secrets are never exposed decrypted -The system SHALL prevent decrypted secret values from being sent to the frontend. - -#### Scenario: Secret list display -- **WHEN** the user views the secrets list -- **THEN** only secret keys and scopes are visible -- **AND** values are always masked - -#### Scenario: Secret update -- **WHEN** the user updates a secret -- **THEN** only the new value is sent to the backend -- **AND** the old value is replaced (not displayed) - -### Requirement: User can delete secrets -The system SHALL allow deletion of secret values. - -#### Scenario: Delete secret -- **WHEN** the user deletes a secret -- **THEN** the encrypted value is permanently removed -- **AND** the secret is no longer injected into containers diff --git a/openspec/changes/config-secrets/tasks.md b/openspec/changes/config-secrets/tasks.md deleted file mode 100644 index a5d5611..0000000 --- a/openspec/changes/config-secrets/tasks.md +++ /dev/null @@ -1,48 +0,0 @@ -## 1. Backend Enhancements - -- [x] 1.1 Update Config model with scope validation methods -- [x] 1.2 Update Secret model with encryption verification -- [x] 1.3 Enhance configs router with scope filtering and hierarchy resolution -- [x] 1.4 Enhance secrets router with scope filtering and hierarchy resolution -- [x] 1.5 Create apps/api/app/services/runtime_injection.py for config/secret resolution -- [x] 1.6 Implement config file generation for container mounts -- [x] 1.7 Implement secret env var generation for container injection -- [x] 1.8 Add validation to fail spawn when referenced secrets are missing - -## 2. Frontend - Config Management - -- [x] 2.1 Create ConfigList component at /projects/:id/configs -- [x] 2.2 Implement ConfigForm for creating/updating configs -- [x] 2.3 Add scope selector (project/instance/global) to config form -- [x] 2.4 Implement config delete with confirmation -- [x] 2.5 Add JSON formatting for config values - -## 3. Frontend - Secret Management - -- [x] 3.1 Create SecretList component at /projects/:id/secrets -- [x] 3.2 Implement SecretForm for creating/updating secrets -- [x] 3.3 Add masked value display (never show decrypted) -- [x] 3.4 Implement secret delete with confirmation -- [x] 3.5 Add scope selector to secret form - -## 4. Runtime Integration - -- [x] 4.1 Integrate runtime injection into tool instance spawn endpoint -- [x] 4.2 Update Docker Compose generation to include config mounts -- [x] 4.3 Update Docker Compose generation to include secret env vars -- [x] 4.4 Test config/secret injection in local Docker environment - -## 5. Testing & Verification - -- [x] 5.1 Write backend tests for config scope resolution -- [x] 5.2 Write backend tests for secret encryption/decryption -- [x] 5.3 Write backend tests for runtime injection -- [x] 5.4 Write frontend tests for ConfigList and SecretList -- [x] 5.5 Run full test suite: `make test` -- [x] 5.6 Run linters: `make lint` - -## 6. Documentation - -- [x] 6.1 Update docs/development.md with config/secrets workflow -- [x] 6.2 Add config/secrets UI guide to docs/architecture.md -- [x] 6.3 Document scope hierarchy and resolution rules diff --git a/openspec/changes/deployment-config/.openspec.yaml b/openspec/changes/deployment-config/.openspec.yaml deleted file mode 100644 index 66dd08a..0000000 --- a/openspec/changes/deployment-config/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-05-14 diff --git a/openspec/changes/deployment-config/design.md b/openspec/changes/deployment-config/design.md deleted file mode 100644 index dce0dfd..0000000 --- a/openspec/changes/deployment-config/design.md +++ /dev/null @@ -1,67 +0,0 @@ -## Context - -The platform routes tool instances via Traefik using subdomain patterns like `https://{tool}-{project}-{user}.{tool_domain}`. Currently, there's no automated label generation or production deployment configuration. This design establishes the deployment architecture. - -Current state: -- `docker-compose.yml` for local dev only -- `docker-compose.traefik.yml` exists but is minimal -- `deploy/` directory has skeleton files -- No automated Traefik label generation - -## Goals / Non-Goals - -**Goals:** -- Generate Traefik labels automatically when spawning tools -- Provide production-ready Docker Compose stack -- Support Portainer-managed deployment -- Enable HTTPS with automatic certificate management - -**Non-Goals:** -- Kubernetes deployment (deferred post-MVP) -- Multi-region or high-availability setup -- Custom reverse proxy (Traefik is the only supported option) -- Automatic DNS management - -## Decisions - -**1. Label generation in backend, not in Docker Compose** -- Rationale: Backend has all metadata (user slug, project slug, tool ID). Generating labels at spawn time is more flexible than static Compose files. -- Implementation: `TraefikLabelGenerator` service class - -**2. Subdomain pattern: `{tool}-{project}-{user}.{domain}`** -- Rationale: Unique, deterministic, human-readable -- Example: `code-server-myapp-alice.headquarter.example.com` - -**3. Separate Docker networks: `platform` and `tools`** -- Rationale: Network isolation between platform services and user tools -- Platform network: API, web, Traefik, database -- Tools network: Traefik + tool containers only - -**4. Portainer as the deployment target** -- Rationale: Docker Compose-native, web UI for operators, supports stacks and webhooks -- Alternative: Raw Docker Compose on VM - less operator-friendly - -**5. Let's Encrypt for HTTPS in production** -- Rationale: Free, automatic, Traefik has built-in support -- Alternative: Custom certificates - adds operational burden - -## Risks / Trade-offs - -**[Risk] Traefik label complexity grows with features** -→ Mitigation: Keep label generation centralized in one service class. Test label output against Traefik schema. - -**[Risk] Portainer stack updates require downtime** -→ Mitigation: Use rolling updates where possible. Document blue-green deployment strategy. - -**[Risk] Subdomain collision** -→ Mitigation: Enforce unique project slugs per user. Include user slug in subdomain. - -## Migration Plan - -No migration - new deployment stack is additive. - -## Open Questions - -1. Should we support custom domains per user/project in MVP? -2. Do we need basic auth or IP allow-listing for Traefik dashboard? -3. Should tool containers run on a separate Docker daemon for security? diff --git a/openspec/changes/deployment-config/proposal.md b/openspec/changes/deployment-config/proposal.md deleted file mode 100644 index 50d060e..0000000 --- a/openspec/changes/deployment-config/proposal.md +++ /dev/null @@ -1,31 +0,0 @@ -## Why - -The scaffold provides local Docker Compose development (FN-002) but lacks production deployment configuration. Without Traefik label generation and production stacks, tool instances cannot receive HTTPS subdomains, blocking the core value proposition of the platform. - -## What Changes - -- **Traefik label generator**: Backend service that generates Docker labels for subdomain routing based on tool instance metadata -- **Production Docker Compose stack**: `docker-compose.prod.yml` with API, web, Traefik, and PostgreSQL services -- **Portainer stack definition**: Docker Compose file optimized for Portainer deployment -- **Dynamic subdomain routing**: Automatic Traefik rule generation for spawned tool containers -- **HTTPS configuration**: Let's Encrypt or custom certificate support via Traefik -- **Network isolation**: Separate Docker networks for platform and tool containers - -## Capabilities - -### New Capabilities -- `traefik-label-generator`: Generate Traefik Docker labels for tool subdomain routing -- `production-compose-stack`: Production Docker Compose configuration -- `portainer-deployment`: Portainer-friendly stack definition and deployment guide -- `subdomain-routing`: Dynamic HTTPS subdomain allocation for tool instances - -### Modified Capabilities -- None (this extends the existing deployment skeleton) - -## Impact - -- **apps/api/app/services/**: New Traefik label generation service -- **apps/api/app/routers/tool_instances.py**: Integrate label generation on spawn -- **deploy/**: New production deployment files -- **docker-compose.prod.yml**: Production stack definition -- **docs/deployment.md**: Updated deployment instructions diff --git a/openspec/changes/deployment-config/specs/portainer-deployment/spec.md b/openspec/changes/deployment-config/specs/portainer-deployment/spec.md deleted file mode 100644 index ae3ec1c..0000000 --- a/openspec/changes/deployment-config/specs/portainer-deployment/spec.md +++ /dev/null @@ -1,22 +0,0 @@ -## ADDED Requirements - -### Requirement: Stack deploys via Portainer -The system SHALL provide a Portainer-compatible stack definition. - -#### Scenario: Portainer stack file -- **WHEN** an operator deploys via Portainer -- **THEN** they can paste the stack definition into Portainer's stack editor -- **AND** Portainer can pull and deploy all services - -#### Scenario: Environment variables in Portainer -- **WHEN** the stack is deployed via Portainer -- **THEN** environment variables are configured in Portainer's UI -- **AND** the stack references these variables - -### Requirement: Deployment documentation is complete -The system SHALL provide operator documentation for deployment. - -#### Scenario: Deployment guide -- **WHEN** an operator reads docs/deployment.md -- **THEN** they find step-by-step instructions for Portainer deployment -- **AND** prerequisites and assumptions are clearly stated diff --git a/openspec/changes/deployment-config/specs/production-compose-stack/spec.md b/openspec/changes/deployment-config/specs/production-compose-stack/spec.md deleted file mode 100644 index 29f8079..0000000 --- a/openspec/changes/deployment-config/specs/production-compose-stack/spec.md +++ /dev/null @@ -1,28 +0,0 @@ -## ADDED Requirements - -### Requirement: Production stack includes all required services -The system SHALL provide a production Docker Compose stack with API, web, Traefik, and PostgreSQL. - -#### Scenario: Stack services -- **WHEN** the production stack is deployed -- **THEN** the following services run: api, web, traefik, db -- **AND** Traefik routes requests to the appropriate service -- **AND** services communicate via isolated Docker networks - -#### Scenario: Environment configuration -- **WHEN** the stack starts -- **THEN** it reads environment variables from .env -- **AND** sensitive values are not hardcoded - -### Requirement: Production stack is secure by default -The system SHALL configure security headers and access controls in production. - -#### Scenario: HTTPS only -- **WHEN** the stack runs in production -- **THEN** all traffic uses HTTPS -- **AND** HTTP redirects to HTTPS - -#### Scenario: Network isolation -- **WHEN** the stack is deployed -- **THEN** platform services and tool containers are on separate networks -- **AND** tool containers cannot access the database directly diff --git a/openspec/changes/deployment-config/specs/subdomain-routing/spec.md b/openspec/changes/deployment-config/specs/subdomain-routing/spec.md deleted file mode 100644 index 9735e26..0000000 --- a/openspec/changes/deployment-config/specs/subdomain-routing/spec.md +++ /dev/null @@ -1,23 +0,0 @@ -## ADDED Requirements - -### Requirement: Each tool instance gets a unique subdomain -The system SHALL assign a unique HTTPS subdomain to each running tool instance. - -#### Scenario: Subdomain pattern -- **WHEN** a tool instance is spawned -- **THEN** its subdomain follows `{tool}-{project}-{user}.{domain}` -- **AND** the subdomain is deterministic based on instance metadata - -#### Scenario: Subdomain accessibility -- **WHEN** a tool instance reaches running status -- **THEN** its subdomain resolves via DNS -- **AND** Traefik routes the subdomain to the container -- **AND** the user can access the tool via the subdomain URL - -### Requirement: Subdomain is released on stop -The system SHALL remove Traefik routing when a tool instance stops. - -#### Scenario: Stop removes routing -- **WHEN** a tool instance is stopped -- **THEN** Traefik labels are removed or disabled -- **AND** the subdomain no longer routes to the container diff --git a/openspec/changes/deployment-config/specs/traefik-label-generator/spec.md b/openspec/changes/deployment-config/specs/traefik-label-generator/spec.md deleted file mode 100644 index c69803a..0000000 --- a/openspec/changes/deployment-config/specs/traefik-label-generator/spec.md +++ /dev/null @@ -1,24 +0,0 @@ -## ADDED Requirements - -### Requirement: Tool spawn generates Traefik labels -The system SHALL generate Docker labels for Traefik when spawning a tool instance. - -#### Scenario: Label generation on spawn -- **WHEN** a tool instance is spawned -- **THEN** the backend generates Traefik router and service labels -- **AND** labels include rule, service, port, and TLS configuration -- **AND** labels are stored with the tool instance metadata - -#### Scenario: Label format -- **WHEN** labels are generated for a tool instance -- **THEN** router rule uses Host(`{subdomain}.{domain}`) -- **AND** service points to the container's exposed port -- **AND** TLS is enabled with certResolver - -### Requirement: Label generation handles multiple instances -The system SHALL generate unique labels for each tool instance. - -#### Scenario: Unique router names -- **WHEN** multiple instances of the same tool exist -- **THEN** each instance gets a unique router name -- **AND** no label collisions occur diff --git a/openspec/changes/deployment-config/tasks.md b/openspec/changes/deployment-config/tasks.md deleted file mode 100644 index 8f66045..0000000 --- a/openspec/changes/deployment-config/tasks.md +++ /dev/null @@ -1,44 +0,0 @@ -## 1. Traefik Label Generator - -- [x] 1.1 Create apps/api/app/services/traefik.py with TraefikLabelGenerator class -- [x] 1.2 Implement subdomain generation from tool_id, project_slug, user_slug -- [x] 1.3 Generate router labels (rule, service, tls) -- [x] 1.4 Generate service labels (loadBalancer, port) -- [x] 1.5 Add middleware labels for security headers -- [x] 1.6 Write unit tests for label generation - -## 2. Backend Integration - -- [x] 2.1 Integrate label generation into tool instance spawn endpoint -- [x] 2.2 Store generated labels in tool_instance metadata -- [x] 2.3 Remove/disable labels on tool instance stop -- [x] 2.4 Update ToolInstance model to store labels JSON - -## 3. Production Docker Compose - -- [x] 3.1 Create docker-compose.prod.yml with api, web, traefik, db services -- [x] 3.2 Configure Traefik service with Let's Encrypt certificates -- [x] 3.3 Set up platform and tools networks -- [x] 3.4 Add health checks for all services -- [x] 3.5 Configure logging (JSON format, rotation) - -## 4. Portainer Deployment - -- [x] 4.1 Create deploy/portainer-stack.yml -- [x] 4.2 Add Portainer-specific environment variable documentation -- [x] 4.3 Create deploy/.env.example for production -- [x] 4.4 Test stack deployment locally with docker compose -f docker-compose.prod.yml - -## 5. Documentation - -- [x] 5.1 Update docs/deployment.md with production deployment steps -- [x] 5.2 Add Traefik configuration guide -- [x] 5.3 Document subdomain scheme and DNS requirements -- [x] 5.4 Update README.md with deployment section - -## 6. Testing & Verification - -- [x] 6.1 Test label generation for all built-in tools -- [x] 6.2 Verify Traefik routes correctly in local stack -- [x] 6.3 Run backend tests: `cd apps/api && pytest` -- [x] 6.4 Run linters: `ruff check app/` and `mypy app/` diff --git a/openspec/changes/runfusion-poc/.openspec.yaml b/openspec/changes/runfusion-poc/.openspec.yaml deleted file mode 100644 index 66dd08a..0000000 --- a/openspec/changes/runfusion-poc/.openspec.yaml +++ /dev/null @@ -1,2 +0,0 @@ -schema: spec-driven -created: 2026-05-14 diff --git a/openspec/changes/runfusion-poc/design.md b/openspec/changes/runfusion-poc/design.md deleted file mode 100644 index 97d16af..0000000 --- a/openspec/changes/runfusion-poc/design.md +++ /dev/null @@ -1,65 +0,0 @@ -## Context - -OpenCode is an AI-powered terminal-based development environment with a web interface. Unlike code-server which is a full web IDE, OpenCode provides a terminal experience accessible through the browser. This POC validates that the spawn system handles different runtime types including web terminal forwarding. - -Current state: -- OpenCode manifest exists in apps/api/app/tools/manifests/opencode.yml -- No container image or runtime defined yet -- No health reporting mechanism -- Spawn infrastructure will be built in FN-010 - -## Goals / Non-Goals - -**Goals:** -- Define OpenCode as a spawnable tool -- Provide web terminal interface in container -- Report health status (running/idle/error) -- Support interactive terminal sessions - -**Non-Goals:** -- Full task queue or job scheduler -- Persistent process management -- Log streaming (deferred) -- Multi-language support beyond terminal - -## Decisions - -**1. Use official OpenCode Docker image** -- Rationale: Maintained, includes AI features and web terminal -- Alternative: Custom image - unnecessary for POC - -**2. OpenCode runs as a persistent container** -- Rationale: Easier to manage lifecycle (start/stop/status). Terminal sessions need persistent container. -- Implementation: Container runs OpenCode with web interface on port 3000 - -**3. Health check via HTTP endpoint** -- Rationale: Standard Docker health check mechanism. Traefik can use it. -- Endpoint: `GET /` returns 200 when ready - -**4. Workspace mounted from host (same as code-server)** -- Rationale: Consistency. Shared workspace between tools. -- Path: `/data/workspaces/{user_slug}/{project_slug}` - -**5. Configs/secrets injected same as code-server** -- Rationale: Reuse FN-009 infrastructure. No special handling needed. - -## Risks / Trade-offs - -**[Risk] OpenCode container requires significant resources** -→ Mitigation: Set resource limits (4GB RAM, 2 CPU). Document requirements. - -**[Risk] Web terminal performance over slow connections** -→ Mitigation: Use modern terminal emulation with compression. Document bandwidth requirements. - -**[Risk] AI features require API keys** -→ Mitigation: Support secret injection for API keys. Document configuration. - -## Migration Plan - -No migration. New feature. - -## Open Questions - -1. Should OpenCode support multiple terminal sessions? -2. Do we pre-configure common development tools? -3. Should OpenCode integrate with the platform's AI provider? diff --git a/openspec/changes/runfusion-poc/proposal.md b/openspec/changes/runfusion-poc/proposal.md deleted file mode 100644 index 753f95b..0000000 --- a/openspec/changes/runfusion-poc/proposal.md +++ /dev/null @@ -1,28 +0,0 @@ -## Why - -OpenCode is an AI-powered terminal-based development environment that provides a web interface for interactive development. It demonstrates the platform's extensibility beyond standard tools like code-server. As a POC, it validates the manifest-driven spawn system with a non-trivial runtime that requires web terminal forwarding. - -## What Changes - -- **OpenCode manifest**: Define the tool with terminal web interface, workspace mounts, and health checks -- **Container image**: Reference to OpenCode image with built-in web terminal -- **Health reporting**: Endpoint that reports tool health to the platform -- **Spawn integration**: Reuse the spawn flow from FN-010 but with OpenCode-specific configuration -- **Web terminal**: Support for browser-based terminal access - -## Capabilities - -### New Capabilities -- `opencode-manifest`: OpenCode tool manifest with web terminal config -- `web-terminal`: Support for browser-based terminal interfaces -- `health-reporting`: Tool health status reporting mechanism - -### Modified Capabilities -- None (reuses spawn infrastructure from FN-010) - -## Impact - -- **apps/api/app/tools/manifests/opencode.yml**: Updated manifest -- **apps/api/app/services/spawn.py**: Minor updates for OpenCode-specific mounts -- **apps/web/src/**: OpenCode appears in tool selection UI -- **Docker images**: Uses official OpenCode image diff --git a/openspec/changes/runfusion-poc/specs/executable-environment/spec.md b/openspec/changes/runfusion-poc/specs/executable-environment/spec.md deleted file mode 100644 index e466f15..0000000 --- a/openspec/changes/runfusion-poc/specs/executable-environment/spec.md +++ /dev/null @@ -1,27 +0,0 @@ -## ADDED Requirements - -### Requirement: Container provides web terminal interface -The system SHALL provide a web terminal interface in the OpenCode container. - -#### Scenario: Terminal available -- **WHEN** the OpenCode container is running -- **THEN** a web terminal is accessible via HTTP on port 3000 -- **AND** the user can execute shell commands through the browser - -#### Scenario: Workspace access -- **WHEN** the container runs -- **THEN** the project workspace is mounted at /workspace -- **AND** the user can read/write files in the workspace - -### Requirement: Container supports AI features -The system SHALL allow AI-powered development features in the OpenCode environment. - -#### Scenario: AI assistance -- **WHEN** the user interacts with OpenCode -- **THEN** AI features are available for code completion and assistance -- **AND** the user can configure AI provider settings - -#### Scenario: Terminal session persistence -- **WHEN** the user opens a terminal session -- **THEN** the session persists while the container runs -- **AND** multiple sessions can be opened diff --git a/openspec/changes/runfusion-poc/specs/health-reporting/spec.md b/openspec/changes/runfusion-poc/specs/health-reporting/spec.md deleted file mode 100644 index c902a89..0000000 --- a/openspec/changes/runfusion-poc/specs/health-reporting/spec.md +++ /dev/null @@ -1,22 +0,0 @@ -## ADDED Requirements - -### Requirement: Tool reports health status -The system SHALL provide a mechanism for OpenCode to report its health. - -#### Scenario: Health endpoint -- **WHEN** the OpenCode container is running -- **THEN** it exposes a / endpoint for health checks -- **AND** returns 200 when the web terminal is ready - -#### Scenario: Health check in Traefik -- **WHEN** the container is spawned -- **THEN** Traefik uses the health endpoint for routing decisions -- **AND** unhealthy containers are removed from the load balancer - -### Requirement: Platform tracks tool health -The system SHALL track and display the health of OpenCode instances. - -#### Scenario: Status display -- **WHEN** the user views an OpenCode instance -- **THEN** the current status is displayed (healthy, unhealthy, starting) -- **AND** the status updates automatically diff --git a/openspec/changes/runfusion-poc/specs/runfusion-manifest/spec.md b/openspec/changes/runfusion-poc/specs/runfusion-manifest/spec.md deleted file mode 100644 index 168c526..0000000 --- a/openspec/changes/runfusion-poc/specs/runfusion-manifest/spec.md +++ /dev/null @@ -1,15 +0,0 @@ -## ADDED Requirements - -### Requirement: OpenCode manifest defines web terminal environment -The system SHALL provide an OpenCode manifest with web terminal configuration. - -#### Scenario: Manifest includes terminal config -- **WHEN** the OpenCode manifest is loaded -- **THEN** it specifies an OpenCode Docker image with web interface -- **AND** it defines exposed ports for the HTTP interface (port 3000) -- **AND** it defines volume mounts (workspace, config) - -#### Scenario: Manifest includes health check -- **WHEN** the manifest is used for spawning -- **THEN** it defines a health check endpoint -- **AND** specifies health check interval and timeout diff --git a/openspec/changes/runfusion-poc/tasks.md b/openspec/changes/runfusion-poc/tasks.md deleted file mode 100644 index 1a74228..0000000 --- a/openspec/changes/runfusion-poc/tasks.md +++ /dev/null @@ -1,42 +0,0 @@ -## 1. Manifest Definition - -- [x] 1.1 Create apps/api/app/tools/manifests/opencode.yml with web terminal config -- [x] 1.2 Add Docker image (ghcr.io/opencode-ai/opencode:latest), ports (3000), volumes -- [x] 1.3 Add health check configuration to manifest -- [x] 1.4 Validate manifest against ToolManifest schema - -## 2. Container Setup - -- [x] 2.1 Verify OpenCode image availability and configuration -- [x] 2.2 Document web terminal access pattern -- [x] 2.3 Configure environment variables for terminal support -- [x] 2.4 Test container locally with docker run -- [x] 2.5 Verify web terminal accessibility - -## 3. Spawn Integration - -- [x] 3.1 Verify SpawnService (FN-010) can spawn OpenCode instances -- [x] 3.2 Add OpenCode-specific volume mounts (config) -- [x] 3.3 Test spawn via API endpoint -- [x] 3.4 Verify Traefik routing to OpenCode container - -## 4. Frontend Integration - -- [x] 4.1 Add OpenCode to tool selection dropdown -- [x] 4.2 Display OpenCode-specific options in spawn form -- [x] 4.3 Show OpenCode instance status in detail page - -## 5. Testing & Verification - -- [x] 5.1 Test terminal availability in spawned container -- [x] 5.2 Test web interface accessibility -- [x] 5.3 Test health endpoint response -- [x] 5.4 Verify workspace mount is accessible -- [x] 5.5 Run full test suite: `make test` -- [x] 5.6 Run linters: `make lint` - -## 6. Documentation - -- [x] 6.1 Document OpenCode setup in docs/development.md -- [x] 6.2 Add OpenCode usage guide -- [x] 6.3 Document terminal configuration and AI features