chore(openspec): archive completed changes
CI / Web CI (push) Failing after 10s
CI / API CI (push) Failing after 11s

- Archive config-secrets (FN-009) - 31 tasks complete
- Archive runfusion-poc (FN-008) - 25 tasks complete
- Archive deployment-config (FN-006) - 27 tasks complete
- All changes moved to openspec/changes/archive/
This commit is contained in:
2026-05-16 11:33:37 +02:00
parent 5a7b026cbc
commit 8b4784f5ed
22 changed files with 698 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-14
@@ -0,0 +1,63 @@
## 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/<key>.json`
- Secret env: `<KEY>=<decrypted_value>`
**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?
@@ -0,0 +1,29 @@
## 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
@@ -0,0 +1,37 @@
## 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
@@ -0,0 +1,40 @@
## 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
@@ -0,0 +1,37 @@
## 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
@@ -0,0 +1,48 @@
## 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
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-14
@@ -0,0 +1,67 @@
## 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?
@@ -0,0 +1,31 @@
## 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
@@ -0,0 +1,22 @@
## 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
@@ -0,0 +1,28 @@
## 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
@@ -0,0 +1,23 @@
## 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
@@ -0,0 +1,24 @@
## 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
@@ -0,0 +1,44 @@
## 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/`
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-14
@@ -0,0 +1,65 @@
## 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?
@@ -0,0 +1,28 @@
## 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
@@ -0,0 +1,27 @@
## 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
@@ -0,0 +1,22 @@
## 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
@@ -0,0 +1,15 @@
## 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
@@ -0,0 +1,42 @@
## 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