产出prd
This commit is contained in:
parent
834a240fe3
commit
b796a61469
@ -1,5 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@opencode-ai/plugin": "1.1.40"
|
||||
"@opencode-ai/plugin": "1.4.3"
|
||||
}
|
||||
}
|
||||
762
.trellis/tasks/04-17-ops-mvp-design/prd.md
Normal file
762
.trellis/tasks/04-17-ops-mvp-design/prd.md
Normal file
@ -0,0 +1,762 @@
|
||||
# OPS MVP Design
|
||||
|
||||
## Summary
|
||||
|
||||
`opencode-provider-switch` (`ops`) is a local CLI + proxy for OpenCode.
|
||||
|
||||
Its job is narrow:
|
||||
|
||||
- Accept OpenCode traffic on `http://127.0.0.1:9982`
|
||||
- Route requests by protocol, not by provider brand
|
||||
- Retry/fail over across unreliable upstream relay providers
|
||||
- Let multiple upstream providers share one logical model alias
|
||||
- Manage state in SQLite, not in an `ops` config file
|
||||
- Rewrite OpenCode global config to point at the local proxy
|
||||
|
||||
MVP intentionally does **not** try to become a general AI gateway, a dashboard product, or a provider-agnostic orchestration platform.
|
||||
|
||||
## Confirmed Decisions
|
||||
|
||||
- Language: Go
|
||||
- Persistence: SQLite
|
||||
- Default listen address: `127.0.0.1:9982`
|
||||
- Delivery shape: CLI only
|
||||
- MVP protocols:
|
||||
- `openai-chat-completions`
|
||||
- `openai-responses`
|
||||
- Anthropic native protocol: out of MVP
|
||||
- Logical model aliasing: required
|
||||
- Billing/cost accounting: out of MVP
|
||||
- Provider model discovery via `/models`: in MVP, best-effort
|
||||
|
||||
## Product Goals
|
||||
|
||||
1. Keep OpenCode usable when cheap relay providers fail intermittently.
|
||||
2. Reduce OpenCode config complexity by centralizing provider management in `ops`.
|
||||
3. Make failover behavior predictable, visible, and debuggable.
|
||||
4. Preserve OpenCode-native workflow instead of asking users to switch tools.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
1. No GUI, web dashboard, or hosted control plane.
|
||||
2. No Anthropic native API support in MVP.
|
||||
3. No automatic price tracking or billing reconciliation.
|
||||
4. No smart routing based on prompt content, latency scoring, or cost optimization.
|
||||
5. No distributed/high-availability deployment story.
|
||||
6. No attempt to normalize every provider quirk in MVP.
|
||||
|
||||
## Why Go
|
||||
|
||||
Go is the right fit for this product shape:
|
||||
|
||||
- `net/http` is strong enough for proxying and streaming without extra framework weight.
|
||||
- Cross-platform static builds are straightforward.
|
||||
- SQLite works well as a local state store.
|
||||
- CLI ergonomics are mature with `cobra`.
|
||||
- Concurrency model is a good fit for retries, request cancellation, and stream handling.
|
||||
|
||||
## Core Design Principle
|
||||
|
||||
`ops` should manage **protocol pools** and **logical aliases**, not raw provider selection inside OpenCode.
|
||||
|
||||
OpenCode should see a small number of local proxy providers. `ops` should own:
|
||||
|
||||
- upstream providers
|
||||
- API keys and headers
|
||||
- failover order
|
||||
- alias to provider-model mapping
|
||||
- model discovery cache
|
||||
|
||||
This keeps OpenCode config stable even when upstream providers are added, removed, or reprioritized.
|
||||
|
||||
## High-Level Architecture
|
||||
|
||||
```text
|
||||
OpenCode
|
||||
-> local OpenAI-compatible provider config
|
||||
-> ops proxy (127.0.0.1:9982)
|
||||
-> protocol router
|
||||
-> alias resolver
|
||||
-> failover engine
|
||||
-> upstream relay provider A / B / C
|
||||
```
|
||||
|
||||
### Major Components
|
||||
|
||||
1. `cli`
|
||||
- all user-facing commands
|
||||
- install, restore, provider management, alias management, doctor, serve
|
||||
|
||||
2. `sqlite store`
|
||||
- source of truth for providers, aliases, protocol pools, model cache, install state
|
||||
|
||||
3. `proxy server`
|
||||
- handles incoming HTTP requests from OpenCode
|
||||
- supports streaming and non-streaming pass-through
|
||||
|
||||
4. `router`
|
||||
- resolves protocol + alias -> ordered upstream targets
|
||||
|
||||
5. `failover engine`
|
||||
- sequentially tries candidate targets based on priority and failure policy
|
||||
|
||||
6. `opencode integration`
|
||||
- imports current OpenCode config
|
||||
- writes generated proxy-backed OpenCode config
|
||||
- restores backup when requested
|
||||
|
||||
7. `model discovery`
|
||||
- fetches raw `/models` data from providers
|
||||
- stores normalized cache for alias creation and diagnostics
|
||||
|
||||
## Supported Protocols in MVP
|
||||
|
||||
### 1. OpenAI Chat Completions
|
||||
|
||||
- Incoming route: `POST /v1/chat/completions`
|
||||
- Discovery route: `GET /v1/models`
|
||||
- OpenCode provider package: `@ai-sdk/openai-compatible`
|
||||
|
||||
### 2. OpenAI Responses
|
||||
|
||||
- Incoming route: `POST /v1/responses`
|
||||
- Discovery route: `GET /v1/models`
|
||||
- OpenCode provider package: `@ai-sdk/openai`
|
||||
|
||||
## Critical Scope Constraint
|
||||
|
||||
Even though both protocols are OpenAI-family APIs, they are **not** interchangeable at the OpenCode config level.
|
||||
|
||||
For MVP, `ops` should expose two local providers to OpenCode:
|
||||
|
||||
- one chat-completions provider
|
||||
- one responses provider
|
||||
|
||||
This mirrors how OpenCode expects provider wiring today and avoids hidden protocol translation logic inside `ops`.
|
||||
|
||||
## OpenCode Integration Strategy
|
||||
|
||||
### Generated OpenCode Config
|
||||
|
||||
`ops install` should rewrite the user's global OpenCode config so that OpenCode points to local proxy providers instead of raw upstream relays.
|
||||
|
||||
Generated provider shape should be conceptually like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"provider": {
|
||||
"ops-chat": {
|
||||
"npm": "@ai-sdk/openai-compatible",
|
||||
"name": "OPS Chat",
|
||||
"options": {
|
||||
"baseURL": "http://127.0.0.1:9982/v1",
|
||||
"apiKey": "ops-local"
|
||||
},
|
||||
"models": {
|
||||
"gpt-5.4": {
|
||||
"name": "gpt-5.4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ops-responses": {
|
||||
"npm": "@ai-sdk/openai",
|
||||
"name": "OPS Responses",
|
||||
"options": {
|
||||
"baseURL": "http://127.0.0.1:9982/v1",
|
||||
"apiKey": "ops-local"
|
||||
},
|
||||
"models": {
|
||||
"gpt-5.4": {
|
||||
"name": "gpt-5.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"model": "ops-responses/gpt-5.4",
|
||||
"small_model": "ops-chat/gpt-5.4-mini"
|
||||
}
|
||||
```
|
||||
|
||||
### Important Rule
|
||||
|
||||
`ops` should preserve as much of the user's existing OpenCode config as possible.
|
||||
|
||||
`ops install` should:
|
||||
|
||||
1. Back up current global config file.
|
||||
2. Import provider/model information relevant to migration.
|
||||
3. Preserve unrelated keys like `plugin`, `agent`, `formatter`, `permission`, `instructions`, and other user settings.
|
||||
4. Replace only the parts that need to point to local proxy providers:
|
||||
- `provider`
|
||||
- `model`
|
||||
- `small_model`
|
||||
|
||||
### Project Config Limitation
|
||||
|
||||
OpenCode merges config from multiple sources, and project config can override global config.
|
||||
|
||||
That means `ops install` cannot guarantee full interception if a repository-local `opencode.json` or environment override replaces provider/model settings.
|
||||
|
||||
MVP response:
|
||||
|
||||
- document this clearly
|
||||
- make `ops doctor` detect likely overrides
|
||||
- support global install first
|
||||
|
||||
Do **not** promise perfect takeover across all OpenCode precedence layers in MVP.
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Input Sources
|
||||
|
||||
`ops install` should inspect:
|
||||
|
||||
1. `~/.config/opencode/opencode.json`
|
||||
2. `~/.config/opencode/opencode.jsonc`
|
||||
3. `~/.local/share/opencode/auth.json` when present
|
||||
|
||||
Reason:
|
||||
|
||||
- some users store `apiKey` inline in config
|
||||
- OpenCode official flow often stores credentials in `auth.json`
|
||||
|
||||
### Migration Behavior
|
||||
|
||||
For each imported provider/model entry from OpenCode:
|
||||
|
||||
1. Determine whether it is chat-completions-oriented or responses-oriented.
|
||||
2. Create an upstream provider record in SQLite.
|
||||
3. Create logical aliases from existing model names.
|
||||
4. Preserve model metadata when available from config:
|
||||
- display name
|
||||
- limit
|
||||
- attachment
|
||||
- reasoning
|
||||
- tool_call
|
||||
- options
|
||||
- variants
|
||||
5. Generate local `ops-*` providers for OpenCode.
|
||||
|
||||
### Protocol Classification
|
||||
|
||||
Import classification rules for MVP:
|
||||
|
||||
- `@ai-sdk/openai-compatible` -> `openai-chat-completions`
|
||||
- `@ai-sdk/openai` -> `openai-responses`
|
||||
- everything else -> unsupported for automatic migration in MVP
|
||||
|
||||
If unsupported providers exist, `ops install` should warn and skip them instead of guessing.
|
||||
|
||||
## SQLite-First State Model
|
||||
|
||||
`ops` should not keep its own user-editable config file.
|
||||
|
||||
Recommended database path:
|
||||
|
||||
- Linux/WSL: `~/.local/share/ops/ops.db`
|
||||
- Windows native: use `os.UserConfigDir()` or `os.UserCacheDir()`-appropriate app path, finalized in implementation
|
||||
|
||||
The generated OpenCode config file is an output artifact, not `ops` source of truth.
|
||||
|
||||
### Proposed Tables
|
||||
|
||||
#### `providers`
|
||||
|
||||
Stores upstream provider connection info.
|
||||
|
||||
Suggested columns:
|
||||
|
||||
- `id`
|
||||
- `name`
|
||||
- `protocol`
|
||||
- `base_url`
|
||||
- `api_key`
|
||||
- `headers_json`
|
||||
- `priority`
|
||||
- `enabled`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
#### `provider_models`
|
||||
|
||||
Stores raw models discovered from upstream or imported from OpenCode config.
|
||||
|
||||
Suggested columns:
|
||||
|
||||
- `id`
|
||||
- `provider_id`
|
||||
- `remote_model_id`
|
||||
- `display_name`
|
||||
- `source`
|
||||
- `raw_json`
|
||||
- `last_seen_at`
|
||||
|
||||
#### `aliases`
|
||||
|
||||
Stores user-facing logical model names per protocol.
|
||||
|
||||
Suggested columns:
|
||||
|
||||
- `id`
|
||||
- `protocol`
|
||||
- `alias`
|
||||
- `display_name`
|
||||
- `capabilities_json`
|
||||
- `limits_json`
|
||||
- `options_json`
|
||||
- `variants_json`
|
||||
- `enabled`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
#### `alias_targets`
|
||||
|
||||
Maps one logical alias to one or more provider-specific targets.
|
||||
|
||||
Suggested columns:
|
||||
|
||||
- `id`
|
||||
- `alias_id`
|
||||
- `provider_id`
|
||||
- `remote_model_id`
|
||||
- `priority`
|
||||
- `enabled`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
#### `install_state`
|
||||
|
||||
Tracks OpenCode integration state.
|
||||
|
||||
Suggested columns:
|
||||
|
||||
- `id`
|
||||
- `backup_path`
|
||||
- `managed_config_path`
|
||||
- `installed_at`
|
||||
- `last_generated_at`
|
||||
- `original_config_hash`
|
||||
- `generated_config_hash`
|
||||
|
||||
#### `request_log`
|
||||
|
||||
Optional but useful even in MVP for debugging. Keep retention small.
|
||||
|
||||
Suggested columns:
|
||||
|
||||
- `id`
|
||||
- `protocol`
|
||||
- `alias`
|
||||
- `provider_id`
|
||||
- `remote_model_id`
|
||||
- `attempt`
|
||||
- `result`
|
||||
- `status_code`
|
||||
- `duration_ms`
|
||||
- `error_text`
|
||||
- `created_at`
|
||||
|
||||
## Model Alias Design
|
||||
|
||||
Alias support is a core MVP feature, not a nice-to-have.
|
||||
|
||||
Example:
|
||||
|
||||
- logical alias: `gpt-5.4`
|
||||
- responses target priority 1: provider `su8`, remote model `gpt-5.4`
|
||||
- responses target priority 2: provider `codex-for-me`, remote model `GPT-5.4`
|
||||
- chat target priority 1: provider `relay-x`, remote model `gpt-5.4-chat`
|
||||
|
||||
This allows the user to keep using one stable model name inside OpenCode while `ops` handles provider-specific naming.
|
||||
|
||||
### Important Constraint
|
||||
|
||||
Aliases should be scoped by protocol.
|
||||
|
||||
`gpt-5.4` for chat completions and `gpt-5.4` for responses may exist simultaneously, but they should resolve through separate alias records or a protocol-aware unique key.
|
||||
|
||||
This avoids accidental cross-protocol reuse.
|
||||
|
||||
## `/models` Discovery Design
|
||||
|
||||
### Purpose
|
||||
|
||||
Reduce manual provider setup work.
|
||||
|
||||
### Behavior
|
||||
|
||||
`ops` should be able to call upstream `GET /v1/models` and cache results per provider.
|
||||
|
||||
Useful commands:
|
||||
|
||||
- `ops provider models sync <provider>`
|
||||
- `ops provider models list <provider>`
|
||||
- `ops alias suggest <provider>`
|
||||
|
||||
### Important Limitation
|
||||
|
||||
Provider `/models` data is often incomplete or inconsistent.
|
||||
|
||||
It usually does **not** fully describe:
|
||||
|
||||
- context length
|
||||
- output limits
|
||||
- attachment support
|
||||
- reasoning support
|
||||
- tool calling support
|
||||
- custom request options
|
||||
|
||||
So for MVP, `/models` must be treated as:
|
||||
|
||||
- good for raw model ID discovery
|
||||
- not authoritative for OpenCode capability metadata
|
||||
|
||||
This means alias metadata may still need manual editing or migration from prior OpenCode config.
|
||||
|
||||
## Proxy Request Flow
|
||||
|
||||
### Non-Streaming Request
|
||||
|
||||
1. Receive request on `/v1/chat/completions` or `/v1/responses`.
|
||||
2. Parse request body enough to extract `model`.
|
||||
3. Resolve `(protocol, alias)` to ordered alias targets.
|
||||
4. Replace logical alias with provider-specific remote model ID.
|
||||
5. Forward request to highest-priority enabled provider.
|
||||
6. If response is retryable failure, try next target.
|
||||
7. Return first successful response.
|
||||
|
||||
### Streaming Request
|
||||
|
||||
Same as above, with one critical rule:
|
||||
|
||||
- failover is only allowed **before first upstream response byte is sent to the client**
|
||||
|
||||
Once a stream begins successfully, `ops` must stay on that provider for that request.
|
||||
|
||||
## Failover Policy
|
||||
|
||||
MVP failover should stay simple and explicit.
|
||||
|
||||
### Retryable Conditions
|
||||
|
||||
- DNS/connect failure
|
||||
- TCP reset / EOF before response
|
||||
- request timeout
|
||||
- chunk timeout before first byte
|
||||
- HTTP `429`
|
||||
- HTTP `500-599`
|
||||
|
||||
### Non-Retryable Conditions
|
||||
|
||||
- HTTP `400`
|
||||
- HTTP `401`
|
||||
- HTTP `403`
|
||||
- HTTP `404`
|
||||
- request validation errors from upstream after request is accepted
|
||||
|
||||
### Special Case: Model Not Found
|
||||
|
||||
Some providers return `404` or `400` for unknown model IDs.
|
||||
|
||||
MVP should **not** build broad heuristic parsing for this.
|
||||
|
||||
Reason:
|
||||
|
||||
- error bodies are inconsistent
|
||||
- aggressive parsing will create surprising behavior
|
||||
|
||||
Safer MVP rule:
|
||||
|
||||
- do not auto-fail over on ambiguous `400/404`
|
||||
- surface error clearly
|
||||
|
||||
This is conservative, but predictable.
|
||||
|
||||
## Proxy Response Headers
|
||||
|
||||
For debugging, add response headers when possible:
|
||||
|
||||
- `X-OPS-Protocol`
|
||||
- `X-OPS-Alias`
|
||||
- `X-OPS-Provider`
|
||||
- `X-OPS-Remote-Model`
|
||||
- `X-OPS-Attempt`
|
||||
- `X-OPS-Failover-Count`
|
||||
|
||||
These headers are low-cost and help explain behavior fast.
|
||||
|
||||
## Local Proxy Security Model
|
||||
|
||||
MVP security posture should be intentionally modest but clear.
|
||||
|
||||
### Default Behavior
|
||||
|
||||
- bind only to `127.0.0.1`
|
||||
- generated OpenCode config uses local static API key like `ops-local`
|
||||
- proxy accepts only loopback traffic by default
|
||||
|
||||
### Why This Is Acceptable For MVP
|
||||
|
||||
- tool is local-only by default
|
||||
- threat model is mostly accidental exposure, not multi-tenant isolation
|
||||
|
||||
### Caveat
|
||||
|
||||
SQLite-stored API keys are sensitive.
|
||||
|
||||
MVP options:
|
||||
|
||||
1. Store plaintext in SQLite with strict file permissions.
|
||||
2. Defer OS keychain integration to later.
|
||||
|
||||
Recommended MVP choice:
|
||||
|
||||
- plaintext in SQLite
|
||||
- create DB with owner-only permissions where possible
|
||||
- document this explicitly
|
||||
|
||||
Reason:
|
||||
|
||||
- simplest implementation
|
||||
- consistent cross-platform behavior
|
||||
- avoids blocking MVP on secret-store complexity
|
||||
|
||||
## CLI Surface
|
||||
|
||||
Proposed command set:
|
||||
|
||||
### Lifecycle
|
||||
|
||||
- `ops init`
|
||||
- `ops serve`
|
||||
- `ops doctor`
|
||||
- `ops install`
|
||||
- `ops restore`
|
||||
|
||||
### Provider Management
|
||||
|
||||
- `ops provider add`
|
||||
- `ops provider list`
|
||||
- `ops provider edit`
|
||||
- `ops provider remove`
|
||||
- `ops provider enable`
|
||||
- `ops provider disable`
|
||||
|
||||
### Model Discovery
|
||||
|
||||
- `ops provider models sync <provider>`
|
||||
- `ops provider models list <provider>`
|
||||
|
||||
### Alias Management
|
||||
|
||||
- `ops alias add`
|
||||
- `ops alias list`
|
||||
- `ops alias bind`
|
||||
- `ops alias unbind`
|
||||
- `ops alias enable`
|
||||
- `ops alias disable`
|
||||
- `ops alias inspect <alias>`
|
||||
|
||||
### Diagnostics
|
||||
|
||||
- `ops logs tail`
|
||||
- `ops route test --protocol <protocol> --model <alias>`
|
||||
|
||||
## Recommended Minimal UX
|
||||
|
||||
Prefer explicit CLI over magical automation.
|
||||
|
||||
Good path:
|
||||
|
||||
1. `ops init`
|
||||
2. `ops provider add`
|
||||
3. `ops provider models sync`
|
||||
4. `ops alias add`
|
||||
5. `ops alias bind`
|
||||
6. `ops install`
|
||||
7. `ops serve`
|
||||
|
||||
This is easy to explain and easy to debug.
|
||||
|
||||
## Suggested Go Package Layout
|
||||
|
||||
```text
|
||||
cmd/ops/
|
||||
internal/cli/
|
||||
internal/db/
|
||||
internal/models/
|
||||
internal/providers/
|
||||
internal/aliases/
|
||||
internal/proxy/
|
||||
internal/router/
|
||||
internal/failover/
|
||||
internal/opencode/
|
||||
internal/doctor/
|
||||
internal/logging/
|
||||
```
|
||||
|
||||
### Library Choices
|
||||
|
||||
- CLI: `cobra`
|
||||
- SQLite driver: `modernc.org/sqlite`
|
||||
- Logging: stdlib `log/slog`
|
||||
- HTTP: stdlib `net/http`
|
||||
- JSONC parsing for OpenCode config import/export: `tailscale/hujson` or equivalent
|
||||
|
||||
Avoid adding a heavy HTTP framework unless a real need appears.
|
||||
|
||||
## Generated OpenCode Provider Strategy
|
||||
|
||||
MVP should generate only providers that `ops` can actually back.
|
||||
|
||||
That means:
|
||||
|
||||
- `ops-chat`
|
||||
- `ops-responses`
|
||||
|
||||
Do **not** generate fake Anthropic provider entries in MVP.
|
||||
|
||||
Do **not** attempt to preserve original provider IDs inside OpenCode after installation.
|
||||
|
||||
Reason:
|
||||
|
||||
- `ops` becomes the stable local provider boundary
|
||||
- upstream providers should move into SQLite management only
|
||||
|
||||
## WSL / Windows Strategy
|
||||
|
||||
This requirement is important, but it needs careful wording.
|
||||
|
||||
### What MVP Should Promise
|
||||
|
||||
1. Native Linux/WSL build works.
|
||||
2. Native Windows build works.
|
||||
3. Running OpenCode and `ops` in the **same environment** is supported.
|
||||
4. `ops doctor` helps detect config-path and loopback issues.
|
||||
|
||||
### What MVP Should Not Promise Yet
|
||||
|
||||
1. Fully automatic cross-boundary migration between WSL OpenCode and Windows `ops`.
|
||||
2. Transparent path translation for every user setup.
|
||||
3. Zero-config interop when OpenCode runs on one side and proxy on the other.
|
||||
|
||||
### Practical Recommendation
|
||||
|
||||
For MVP, recommend users run OpenCode and `ops` in the same environment.
|
||||
|
||||
Cross-environment support can be added later via explicit install target flags.
|
||||
|
||||
## Biggest Risks
|
||||
|
||||
### 1. OpenCode Config Precedence
|
||||
|
||||
Global config rewrite alone may not capture project-level overrides.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- `ops doctor`
|
||||
- clear docs
|
||||
- possible future `ops install --project`
|
||||
|
||||
### 2. Provider `/models` Quality
|
||||
|
||||
Discovery helps with model IDs, but not with full capability metadata.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- preserve metadata during import
|
||||
- allow manual alias metadata editing
|
||||
|
||||
### 3. Streaming Edge Cases
|
||||
|
||||
Once bytes are sent, failover is no longer safe.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- fail over only before first byte
|
||||
- good timeout defaults
|
||||
- precise logging
|
||||
|
||||
### 4. Secret Storage
|
||||
|
||||
SQLite plaintext credentials are acceptable for MVP, but they are still sensitive.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- strict file permissions
|
||||
- local-only binding
|
||||
- document tradeoff
|
||||
|
||||
### 5. Protocol Ambiguity During Migration
|
||||
|
||||
OpenCode custom providers can mix package usage in ways that are not cleanly inferable.
|
||||
|
||||
Mitigation:
|
||||
|
||||
- support only known package mappings in MVP
|
||||
- warn instead of guessing
|
||||
|
||||
## MVP Success Criteria
|
||||
|
||||
MVP is successful if a user can:
|
||||
|
||||
1. Import existing OpenCode provider setup into `ops`.
|
||||
2. Create or verify aliases for commonly used models.
|
||||
3. Install proxy-backed OpenCode global config.
|
||||
4. Run `ops serve`.
|
||||
5. Use OpenCode normally against `127.0.0.1:9982`.
|
||||
6. Survive common upstream failures by automatic provider failover.
|
||||
|
||||
## Recommended Implementation Order
|
||||
|
||||
### Phase 1
|
||||
|
||||
- bootstrap Go project
|
||||
- SQLite store
|
||||
- provider CRUD
|
||||
- alias CRUD
|
||||
|
||||
### Phase 2
|
||||
|
||||
- `GET /v1/models` sync
|
||||
- import from OpenCode config/auth
|
||||
- generated OpenCode config writer
|
||||
|
||||
### Phase 3
|
||||
|
||||
- proxy server
|
||||
- chat completions forwarding
|
||||
- responses forwarding
|
||||
- non-streaming failover
|
||||
|
||||
### Phase 4
|
||||
|
||||
- streaming support
|
||||
- logging/diagnostics
|
||||
- `ops doctor`
|
||||
- restore flow
|
||||
|
||||
## Strong Recommendation
|
||||
|
||||
Do not start with background health checks, latency scoring, or dynamic routing.
|
||||
|
||||
Start with deterministic priority failover only.
|
||||
|
||||
That gives the product a sharp identity:
|
||||
|
||||
- local
|
||||
- understandable
|
||||
- reliable enough
|
||||
- much smaller than LiteLLM
|
||||
|
||||
## Next Step
|
||||
|
||||
Next practical step is implementation bootstrap for:
|
||||
|
||||
1. Go module structure
|
||||
2. SQLite schema migrations
|
||||
3. Cobra command tree
|
||||
4. OpenCode config importer/exporter
|
||||
|
||||
That is the smallest slice that validates the design without touching complex proxy streaming first.
|
||||
45
.trellis/tasks/04-17-ops-mvp-design/task.json
Normal file
45
.trellis/tasks/04-17-ops-mvp-design/task.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"id": "04-17-ops-mvp-design",
|
||||
"name": "OPS MVP Design",
|
||||
"description": "Define MVP product and technical design for a Go-based local proxy that failsover OpenCode providers",
|
||||
"status": "completed",
|
||||
"dev_type": "docs",
|
||||
"priority": "P1",
|
||||
"creator": "Apale",
|
||||
"assignee": "Apale",
|
||||
"createdAt": "2026-04-17",
|
||||
"completedAt": "2026-04-17",
|
||||
"commit": null,
|
||||
"subtasks": [
|
||||
{
|
||||
"name": "Define MVP scope and non-goals",
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"name": "Define Go architecture and SQLite schema",
|
||||
"status": "completed"
|
||||
},
|
||||
{
|
||||
"name": "Document OpenCode migration and proxy behavior",
|
||||
"status": "completed"
|
||||
}
|
||||
],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [
|
||||
".trellis/tasks/04-17-ops-mvp-design/prd.md",
|
||||
"examples/opencode.jsonc"
|
||||
],
|
||||
"notes": "Design-only task completed. Implementation should start from a follow-up task based on this PRD.",
|
||||
"meta": {
|
||||
"stack": [
|
||||
"Go",
|
||||
"SQLite"
|
||||
],
|
||||
"defaultPort": 9982,
|
||||
"mvpProtocols": [
|
||||
"openai-chat-completions",
|
||||
"openai-responses"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user