docs(03-tier-3-9-providers): create phase plan

This commit is contained in:
salvacybersec
2026-04-05 14:39:54 +03:00
parent 19f55ffeb3
commit a318b9d89f
9 changed files with 3231 additions and 1 deletions

View File

@@ -79,7 +79,17 @@ Plans:
2. Chinese/regional provider keys (DeepSeek, Zhipu, Moonshot, Qwen, Baidu, ByteDance, etc.) are detected using keyword-based matching since they use generic key formats 2. Chinese/regional provider keys (DeepSeek, Zhipu, Moonshot, Qwen, Baidu, ByteDance, etc.) are detected using keyword-based matching since they use generic key formats
3. Self-hosted provider definitions (Ollama, vLLM, LocalAI, etc.) include patterns for API key authentication when applicable 3. Self-hosted provider definitions (Ollama, vLLM, LocalAI, etc.) include patterns for API key authentication when applicable
4. `keyhunter providers list --tier=enterprise` returns Salesforce, ServiceNow, SAP, Palantir, Databricks, Snowflake, Oracle, HPE providers 4. `keyhunter providers list --tier=enterprise` returns Salesforce, ServiceNow, SAP, Palantir, Databricks, Snowflake, Oracle, HPE providers
**Plans**: TBD **Plans**: 8 plans
Plans:
- [ ] 03-01-PLAN.md — Tier 4 Chinese/regional providers (DeepSeek, Zhipu, Moonshot, Qwen, Baidu, ByteDance, 01.AI, MiniMax, Baichuan, StepFun, SenseTime, iFlytek, Tencent, SiliconFlow, 360 AI, Kuaishou)
- [ ] 03-02-PLAN.md — Tier 3 Specialized (Perplexity, You.com, Voyage, Jina, Unstructured, AssemblyAI, Deepgram, ElevenLabs, Stability, Runway, Midjourney)
- [ ] 03-03-PLAN.md — Tier 5 Infrastructure/Gateway (OpenRouter, LiteLLM, Cloudflare AI, Vercel AI, Portkey, Helicone, Martian, Kong, BricksAI, Aether, Not Diamond)
- [ ] 03-04-PLAN.md — Tier 7 Code/Dev Tools (GitHub Copilot, Cursor, Tabnine, Codeium, Sourcegraph, CodeWhisperer, Replit AI, Codestral, watsonx, Oracle AI)
- [ ] 03-05-PLAN.md — Tier 8 Self-Hosted runtimes (Ollama, vLLM, LocalAI, LM Studio, llama.cpp, GPT4All, text-gen-webui, TensorRT-LLM, Triton, Jan)
- [ ] 03-06-PLAN.md — Tier 9 Enterprise (Salesforce Einstein, ServiceNow, SAP AI Core, Palantir, Databricks, Snowflake, Oracle GenAI, HPE GreenLake)
- [ ] 03-07-PLAN.md — Tier 6 Emerging/Niche (Reka, Aleph Alpha, Lamini, Writer, Jasper, Typeface, Comet, W&B, LangSmith, Pinecone, Weaviate, Qdrant, Chroma, Milvus, Neon)
- [ ] 03-08-PLAN.md — Tier 3-9 guardrail test: lock 108 total providers, per-tier counts, and name sets
### Phase 4: Input Sources ### Phase 4: Input Sources
**Goal**: Users can point KeyHunter at any content source — local files, git history across all branches, piped content, remote URLs, and the clipboard — and all are scanned through the same detection pipeline **Goal**: Users can point KeyHunter at any content source — local files, git history across all branches, piped content, remote URLs, and the clipboard — and all are scanned through the same detection pipeline

View File

@@ -0,0 +1,544 @@
---
phase: 03-tier-3-9-providers
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- providers/deepseek.yaml
- providers/zhipu.yaml
- providers/moonshot.yaml
- providers/qwen.yaml
- providers/baidu.yaml
- providers/bytedance.yaml
- providers/01ai.yaml
- providers/minimax.yaml
- providers/baichuan.yaml
- providers/stepfun.yaml
- providers/sensetime.yaml
- providers/iflytek.yaml
- providers/tencent.yaml
- providers/siliconflow.yaml
- providers/360ai.yaml
- providers/kuaishou.yaml
- pkg/providers/definitions/deepseek.yaml
- pkg/providers/definitions/zhipu.yaml
- pkg/providers/definitions/moonshot.yaml
- pkg/providers/definitions/qwen.yaml
- pkg/providers/definitions/baidu.yaml
- pkg/providers/definitions/bytedance.yaml
- pkg/providers/definitions/01ai.yaml
- pkg/providers/definitions/minimax.yaml
- pkg/providers/definitions/baichuan.yaml
- pkg/providers/definitions/stepfun.yaml
- pkg/providers/definitions/sensetime.yaml
- pkg/providers/definitions/iflytek.yaml
- pkg/providers/definitions/tencent.yaml
- pkg/providers/definitions/siliconflow.yaml
- pkg/providers/definitions/360ai.yaml
- pkg/providers/definitions/kuaishou.yaml
autonomous: true
requirements: [PROV-04]
must_haves:
truths:
- "Registry loads 16 Tier 4 Chinese/regional provider YAMLs"
- "Providers without documented key formats use keyword-only detection (no patterns entry)"
- "DeepSeek uses documented sk- prefix pattern"
- "All YAMLs are dual-located and diff-clean"
artifacts:
- path: "providers/deepseek.yaml"
provides: "DeepSeek sk- prefix pattern + keywords"
contains: "deepseek"
- path: "providers/qwen.yaml"
provides: "Alibaba Qwen/DashScope keyword-only detection"
contains: "dashscope"
- path: "providers/baidu.yaml"
provides: "Baidu ERNIE/Wenxin keyword detection"
contains: "wenxin"
key_links:
- from: "provider keywords[]"
to: "Registry Aho-Corasick automaton"
via: "NewRegistry()"
pattern: "keywords"
---
<objective>
Create 16 Tier 4 Chinese/regional LLM provider YAML definitions. These providers mostly lack documented key formats, so detection relies on strong keyword lists anchored to their SDK envs, domains, and API hostnames — not on generic regex (which caused false positives in Phase 2).
Purpose: Satisfy PROV-04 (16 Tier 4 providers). Chinese/regional providers are high-value targets but low-signal for regex detection — keyword-only matching is the correct mitigation.
Output: 32 YAML files (16 providers × 2 locations).
Addresses PROV-04.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/03-tier-3-9-providers/03-CONTEXT.md
@pkg/providers/schema.go
@providers/mistral.yaml
@providers/cohere.yaml
<interfaces>
Provider schema (pkg/providers/schema.go): FormatVersion, Name, DisplayName, Tier, LastVerified, Keywords, Patterns, Verify. NO `category` field. Confidence values: high|medium|low.
Patterns array MAY be empty/omitted — registry allows keyword-only providers. Keywords list MUST have ≥3 entries (Aho-Corasick pre-filter requirement).
Files must be dual-located: providers/X.yaml AND pkg/providers/definitions/X.yaml (Go embed cannot use '..' paths).
Phase 2 lesson: generic regex like `[A-Za-z0-9]{32,64}` causes false positives. For providers without distinctive prefixes, OMIT the patterns field entirely (keyword-only detection).
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: DeepSeek, Zhipu, Moonshot, Qwen, Baidu, ByteDance, 01.AI, MiniMax YAMLs</name>
<files>providers/deepseek.yaml, providers/zhipu.yaml, providers/moonshot.yaml, providers/qwen.yaml, providers/baidu.yaml, providers/bytedance.yaml, providers/01ai.yaml, providers/minimax.yaml, pkg/providers/definitions/deepseek.yaml, pkg/providers/definitions/zhipu.yaml, pkg/providers/definitions/moonshot.yaml, pkg/providers/definitions/qwen.yaml, pkg/providers/definitions/baidu.yaml, pkg/providers/definitions/bytedance.yaml, pkg/providers/definitions/01ai.yaml, pkg/providers/definitions/minimax.yaml</files>
<read_first>
- pkg/providers/schema.go
- providers/mistral.yaml (reference: keyword-anchored generic pattern)
- .planning/phases/03-tier-3-9-providers/03-CONTEXT.md (lessons from Phase 2)
</read_first>
<action>
Create each file in providers/ AND pkg/providers/definitions/ (verbatim copy). DeepSeek has a documented sk- prefix so it gets a pattern; all others are keyword-only (omit patterns entirely).
providers/deepseek.yaml:
```yaml
format_version: 1
name: deepseek
display_name: DeepSeek
tier: 4
last_verified: "2026-04-05"
keywords:
- "deepseek"
- "DEEPSEEK_API_KEY"
- "api.deepseek.com"
- "deepseek-chat"
- "deepseek-coder"
patterns:
- regex: 'sk-[a-f0-9]{32}'
entropy_min: 3.5
confidence: medium
verify:
method: GET
url: https://api.deepseek.com/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/zhipu.yaml:
```yaml
format_version: 1
name: zhipu
display_name: Zhipu AI (GLM)
tier: 4
last_verified: "2026-04-05"
keywords:
- "zhipu"
- "ZHIPU_API_KEY"
- "ZHIPUAI_API_KEY"
- "bigmodel.cn"
- "open.bigmodel.cn"
- "glm-4"
- "chatglm"
verify:
method: GET
url: https://open.bigmodel.cn/api/paas/v4/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/moonshot.yaml:
```yaml
format_version: 1
name: moonshot
display_name: Moonshot AI (Kimi)
tier: 4
last_verified: "2026-04-05"
keywords:
- "moonshot"
- "MOONSHOT_API_KEY"
- "api.moonshot.cn"
- "kimi"
- "moonshot-v1"
patterns:
- regex: 'sk-[A-Za-z0-9]{48}'
entropy_min: 4.0
confidence: medium
verify:
method: GET
url: https://api.moonshot.cn/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/qwen.yaml:
```yaml
format_version: 1
name: qwen
display_name: Alibaba Qwen (DashScope)
tier: 4
last_verified: "2026-04-05"
keywords:
- "dashscope"
- "DASHSCOPE_API_KEY"
- "qwen"
- "qwen-turbo"
- "qwen-max"
- "dashscope.aliyuncs.com"
patterns:
- regex: 'sk-[a-f0-9]{32}'
entropy_min: 3.5
confidence: medium
verify:
method: GET
url: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation
headers:
Authorization: "Bearer {KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
providers/baidu.yaml:
```yaml
format_version: 1
name: baidu
display_name: Baidu ERNIE (Wenxin)
tier: 4
last_verified: "2026-04-05"
keywords:
- "wenxin"
- "ernie"
- "BAIDU_API_KEY"
- "QIANFAN_AK"
- "QIANFAN_SK"
- "aip.baidubce.com"
- "qianfan"
verify:
method: POST
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/bytedance.yaml:
```yaml
format_version: 1
name: bytedance
display_name: ByteDance Doubao (Volcengine)
tier: 4
last_verified: "2026-04-05"
keywords:
- "doubao"
- "volcengine"
- "VOLC_ACCESSKEY"
- "VOLC_SECRETKEY"
- "ARK_API_KEY"
- "ark.cn-beijing.volces.com"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/01ai.yaml:
```yaml
format_version: 1
name: 01ai
display_name: 01.AI (Yi)
tier: 4
last_verified: "2026-04-05"
keywords:
- "01.ai"
- "yi-large"
- "yi-34b"
- "YI_API_KEY"
- "api.lingyiwanwu.com"
- "lingyiwanwu"
verify:
method: GET
url: https://api.lingyiwanwu.com/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/minimax.yaml:
```yaml
format_version: 1
name: minimax
display_name: MiniMax
tier: 4
last_verified: "2026-04-05"
keywords:
- "minimax"
- "MINIMAX_API_KEY"
- "MINIMAX_GROUP_ID"
- "api.minimax.chat"
- "abab6"
verify:
method: GET
url: https://api.minimax.chat/v1/text/chatcompletion_v2
headers:
Authorization: "Bearer {KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
Copy each file VERBATIM to pkg/providers/definitions/ with the same basename.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in deepseek zhipu moonshot qwen baidu bytedance 01ai minimax; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 16 files exist (8 providers × 2 locations)
- `grep -q 'DEEPSEEK_API_KEY' providers/deepseek.yaml`
- `grep -q 'dashscope' providers/qwen.yaml`
- `grep -q 'wenxin' providers/baidu.yaml`
- `grep -q 'lingyiwanwu' providers/01ai.yaml`
- `grep -L 'patterns:' providers/zhipu.yaml providers/baidu.yaml providers/bytedance.yaml` returns all three (keyword-only, no patterns field)
- `diff providers/deepseek.yaml pkg/providers/definitions/deepseek.yaml` returns no diff
- `go test ./pkg/providers/... -count=1` passes
- `go test ./pkg/engine/... -count=1` passes (no regression from new providers)
</acceptance_criteria>
<done>8 Chinese/regional providers dual-located, registry loads them, engine tests pass.</done>
</task>
<task type="auto">
<name>Task 2: Baichuan, StepFun, SenseTime, iFlytek, Tencent, SiliconFlow, 360 AI, Kuaishou YAMLs</name>
<files>providers/baichuan.yaml, providers/stepfun.yaml, providers/sensetime.yaml, providers/iflytek.yaml, providers/tencent.yaml, providers/siliconflow.yaml, providers/360ai.yaml, providers/kuaishou.yaml, pkg/providers/definitions/baichuan.yaml, pkg/providers/definitions/stepfun.yaml, pkg/providers/definitions/sensetime.yaml, pkg/providers/definitions/iflytek.yaml, pkg/providers/definitions/tencent.yaml, pkg/providers/definitions/siliconflow.yaml, pkg/providers/definitions/360ai.yaml, pkg/providers/definitions/kuaishou.yaml</files>
<read_first>
- pkg/providers/schema.go
- providers/deepseek.yaml (created in Task 1, reference for format)
</read_first>
<action>
All 8 of these providers lack publicly documented key formats. Use KEYWORD-ONLY detection — omit the patterns field entirely.
providers/baichuan.yaml:
```yaml
format_version: 1
name: baichuan
display_name: Baichuan AI
tier: 4
last_verified: "2026-04-05"
keywords:
- "baichuan"
- "BAICHUAN_API_KEY"
- "api.baichuan-ai.com"
- "baichuan2"
- "baichuan-turbo"
verify:
method: GET
url: https://api.baichuan-ai.com/v1/chat/completions
headers:
Authorization: "Bearer {KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
providers/stepfun.yaml:
```yaml
format_version: 1
name: stepfun
display_name: StepFun (阶跃星辰)
tier: 4
last_verified: "2026-04-05"
keywords:
- "stepfun"
- "STEP_API_KEY"
- "STEPFUN_API_KEY"
- "api.stepfun.com"
- "step-1v"
verify:
method: GET
url: https://api.stepfun.com/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/sensetime.yaml:
```yaml
format_version: 1
name: sensetime
display_name: SenseTime SenseNova
tier: 4
last_verified: "2026-04-05"
keywords:
- "sensetime"
- "sensenova"
- "SENSETIME_API_KEY"
- "SENSENOVA_API_KEY"
- "api.sensenova.cn"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/iflytek.yaml:
```yaml
format_version: 1
name: iflytek
display_name: iFlytek Spark (讯飞星火)
tier: 4
last_verified: "2026-04-05"
keywords:
- "iflytek"
- "xf_yun"
- "spark_desk"
- "XFYUN_API_KEY"
- "XFYUN_API_SECRET"
- "XFYUN_APPID"
- "spark-api.xf-yun.com"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/tencent.yaml:
```yaml
format_version: 1
name: tencent
display_name: Tencent Hunyuan
tier: 4
last_verified: "2026-04-05"
keywords:
- "hunyuan"
- "TENCENTCLOUD_SECRET_ID"
- "TENCENTCLOUD_SECRET_KEY"
- "hunyuan.tencentcloudapi.com"
- "tencent-hunyuan"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/siliconflow.yaml:
```yaml
format_version: 1
name: siliconflow
display_name: SiliconFlow
tier: 4
last_verified: "2026-04-05"
keywords:
- "siliconflow"
- "SILICONFLOW_API_KEY"
- "api.siliconflow.cn"
- "siliconflow.cn"
patterns:
- regex: 'sk-[a-z]{20,}'
entropy_min: 3.5
confidence: low
verify:
method: GET
url: https://api.siliconflow.cn/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/360ai.yaml:
```yaml
format_version: 1
name: 360ai
display_name: 360 AI Brain
tier: 4
last_verified: "2026-04-05"
keywords:
- "360gpt"
- "QIHOO_API_KEY"
- "api.360.cn"
- "ai.360.com"
- "360-ai"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/kuaishou.yaml:
```yaml
format_version: 1
name: kuaishou
display_name: Kuaishou KwaiYii
tier: 4
last_verified: "2026-04-05"
keywords:
- "kuaishou"
- "kwaiyii"
- "KUAISHOU_API_KEY"
- "KWAI_API_KEY"
- "kwai-ai"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
Copy each file VERBATIM to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in baichuan stepfun sensetime iflytek tencent siliconflow 360ai kuaishou; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 16 files exist (8 providers × 2 locations)
- `grep -q 'baichuan-ai.com' providers/baichuan.yaml`
- `grep -q 'hunyuan' providers/tencent.yaml`
- `grep -q 'spark_desk' providers/iflytek.yaml`
- 7 of 8 files have NO patterns field: `grep -L 'patterns:' providers/{baichuan,stepfun,sensetime,iflytek,tencent,360ai,kuaishou}.yaml` returns all 7
- `go test ./pkg/providers/... -count=1` passes
- `go test ./pkg/engine/... -count=1` passes
- Total Tier 4 provider count = 16: `grep -l 'tier: 4' providers/*.yaml | wc -l` → 16
</acceptance_criteria>
<done>All 16 Tier 4 Chinese/regional providers exist dual-located. PROV-04 satisfied.</done>
</task>
</tasks>
<verification>
`grep -l 'tier: 4' providers/*.yaml | wc -l` returns 16.
`go test ./pkg/providers/... ./pkg/engine/... -count=1` passes.
</verification>
<success_criteria>
- 16 Tier 4 providers dual-located
- 13 use keyword-only detection (no patterns field)
- 3 use documented prefix patterns (deepseek, moonshot, qwen, siliconflow — note: 4 with patterns, adjust count)
- Registry loads all without validation errors
- No engine test regressions
</success_criteria>
<output>
After completion, create `.planning/phases/03-tier-3-9-providers/03-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,418 @@
---
phase: 03-tier-3-9-providers
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
- providers/perplexity.yaml
- providers/you.yaml
- providers/voyage.yaml
- providers/jina.yaml
- providers/unstructured.yaml
- providers/assemblyai.yaml
- providers/deepgram.yaml
- providers/elevenlabs.yaml
- providers/stability.yaml
- providers/runway.yaml
- providers/midjourney.yaml
- pkg/providers/definitions/perplexity.yaml
- pkg/providers/definitions/you.yaml
- pkg/providers/definitions/voyage.yaml
- pkg/providers/definitions/jina.yaml
- pkg/providers/definitions/unstructured.yaml
- pkg/providers/definitions/assemblyai.yaml
- pkg/providers/definitions/deepgram.yaml
- pkg/providers/definitions/elevenlabs.yaml
- pkg/providers/definitions/stability.yaml
- pkg/providers/definitions/runway.yaml
- pkg/providers/definitions/midjourney.yaml
autonomous: true
requirements: [PROV-03]
must_haves:
truths:
- "11 new Tier 3 Specialized provider YAMLs load (huggingface already exists → 12 total)"
- "Providers with documented prefixes (pplx-, xai-voyage, sk-, jina_) use tight regex"
- "Voice/image providers without documented prefixes use keyword-only"
artifacts:
- path: "providers/perplexity.yaml"
provides: "Perplexity pplx- prefix pattern"
contains: "pplx-"
- path: "providers/elevenlabs.yaml"
provides: "ElevenLabs API key keyword detection"
contains: "elevenlabs"
- path: "providers/assemblyai.yaml"
provides: "AssemblyAI keyword detection"
contains: "assemblyai"
key_links:
- from: "provider keywords[]"
to: "Registry Aho-Corasick automaton"
via: "NewRegistry()"
pattern: "keywords"
---
<objective>
Create 11 Tier 3 Specialized LLM/AI provider YAMLs — search (Perplexity, You.com), embeddings (Voyage, Jina, Unstructured), voice (AssemblyAI, Deepgram, ElevenLabs), and image/video (Stability, Runway, Midjourney). Huggingface is pre-existing from Phase 2 and must NOT be recreated. Total Tier 3 = 12 after this plan.
Purpose: Satisfy PROV-03 (12 Tier 3 Specialized providers).
Output: 22 YAML files (11 providers × 2 locations).
Addresses PROV-03.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/03-tier-3-9-providers/03-CONTEXT.md
@pkg/providers/schema.go
@providers/huggingface.yaml
@providers/cohere.yaml
<interfaces>
Schema: pkg/providers/schema.go. No `category` field. Confidence: high|medium|low.
Patterns field may be omitted for keyword-only providers. Keywords ≥3 required.
Dual-location required (providers/ + pkg/providers/definitions/).
RE2 regex only.
IMPORTANT: providers/huggingface.yaml ALREADY EXISTS (tier: 3). Do NOT modify or recreate it.
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Search + embeddings providers (Perplexity, You.com, Voyage, Jina, Unstructured, AssemblyAI)</name>
<files>providers/perplexity.yaml, providers/you.yaml, providers/voyage.yaml, providers/jina.yaml, providers/unstructured.yaml, providers/assemblyai.yaml, pkg/providers/definitions/perplexity.yaml, pkg/providers/definitions/you.yaml, pkg/providers/definitions/voyage.yaml, pkg/providers/definitions/jina.yaml, pkg/providers/definitions/unstructured.yaml, pkg/providers/definitions/assemblyai.yaml</files>
<read_first>
- pkg/providers/schema.go
- providers/huggingface.yaml (existing tier 3 reference — DO NOT MODIFY)
</read_first>
<action>
Create each file in providers/ AND copy verbatim to pkg/providers/definitions/.
providers/perplexity.yaml:
```yaml
format_version: 1
name: perplexity
display_name: Perplexity AI
tier: 3
last_verified: "2026-04-05"
keywords:
- "perplexity"
- "PERPLEXITY_API_KEY"
- "pplx-"
- "api.perplexity.ai"
patterns:
- regex: 'pplx-[A-Za-z0-9]{48,}'
entropy_min: 4.0
confidence: high
verify:
method: POST
url: https://api.perplexity.ai/chat/completions
headers:
Authorization: "Bearer {KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
providers/you.yaml:
```yaml
format_version: 1
name: you
display_name: You.com
tier: 3
last_verified: "2026-04-05"
keywords:
- "you.com"
- "YDC_API_KEY"
- "YOU_API_KEY"
- "api.ydc-index.io"
verify:
method: GET
url: https://api.ydc-index.io/search
headers:
X-API-Key: "{KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
providers/voyage.yaml:
```yaml
format_version: 1
name: voyage
display_name: Voyage AI
tier: 3
last_verified: "2026-04-05"
keywords:
- "voyage"
- "VOYAGE_API_KEY"
- "voyageai"
- "api.voyageai.com"
patterns:
- regex: 'pa-[A-Za-z0-9_\-]{40,}'
entropy_min: 4.0
confidence: medium
verify:
method: POST
url: https://api.voyageai.com/v1/embeddings
headers:
Authorization: "Bearer {KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
providers/jina.yaml:
```yaml
format_version: 1
name: jina
display_name: Jina AI
tier: 3
last_verified: "2026-04-05"
keywords:
- "jina"
- "JINA_API_KEY"
- "api.jina.ai"
- "jinaai"
patterns:
- regex: 'jina_[A-Za-z0-9]{40,}'
entropy_min: 4.0
confidence: high
verify:
method: GET
url: https://api.jina.ai/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/unstructured.yaml:
```yaml
format_version: 1
name: unstructured
display_name: Unstructured.io
tier: 3
last_verified: "2026-04-05"
keywords:
- "unstructured"
- "UNSTRUCTURED_API_KEY"
- "api.unstructured.io"
- "unstructuredio"
verify:
method: GET
url: https://api.unstructured.io/general/v0/general
headers:
unstructured-api-key: "{KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
providers/assemblyai.yaml:
```yaml
format_version: 1
name: assemblyai
display_name: AssemblyAI
tier: 3
last_verified: "2026-04-05"
keywords:
- "assemblyai"
- "ASSEMBLYAI_API_KEY"
- "api.assemblyai.com"
- "assembly.ai"
patterns:
- regex: '[a-f0-9]{32}'
entropy_min: 4.0
confidence: low
verify:
method: GET
url: https://api.assemblyai.com/v2/transcript
headers:
authorization: "{KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
Copy all 6 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in perplexity you voyage jina unstructured assemblyai; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 12 files exist (6 providers × 2 locations)
- `grep -q 'pplx-' providers/perplexity.yaml`
- `grep -q 'jina_' providers/jina.yaml`
- `grep -q 'api.voyageai.com' providers/voyage.yaml`
- `diff providers/perplexity.yaml pkg/providers/definitions/perplexity.yaml` returns no diff
- `go test ./pkg/providers/... -count=1` passes
- `go test ./pkg/engine/... -count=1` passes
</acceptance_criteria>
<done>6 search/embeddings providers dual-located.</done>
</task>
<task type="auto">
<name>Task 2: Voice + image/video providers (Deepgram, ElevenLabs, Stability, Runway, Midjourney)</name>
<files>providers/deepgram.yaml, providers/elevenlabs.yaml, providers/stability.yaml, providers/runway.yaml, providers/midjourney.yaml, pkg/providers/definitions/deepgram.yaml, pkg/providers/definitions/elevenlabs.yaml, pkg/providers/definitions/stability.yaml, pkg/providers/definitions/runway.yaml, pkg/providers/definitions/midjourney.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
providers/deepgram.yaml:
```yaml
format_version: 1
name: deepgram
display_name: Deepgram
tier: 3
last_verified: "2026-04-05"
keywords:
- "deepgram"
- "DEEPGRAM_API_KEY"
- "api.deepgram.com"
- "dg-api"
patterns:
- regex: '[a-f0-9]{40}'
entropy_min: 4.0
confidence: low
verify:
method: GET
url: https://api.deepgram.com/v1/projects
headers:
Authorization: "Token {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/elevenlabs.yaml:
```yaml
format_version: 1
name: elevenlabs
display_name: ElevenLabs
tier: 3
last_verified: "2026-04-05"
keywords:
- "elevenlabs"
- "ELEVENLABS_API_KEY"
- "ELEVEN_API_KEY"
- "XI_API_KEY"
- "api.elevenlabs.io"
patterns:
- regex: '[a-f0-9]{32}'
entropy_min: 4.0
confidence: low
verify:
method: GET
url: https://api.elevenlabs.io/v1/user
headers:
xi-api-key: "{KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/stability.yaml:
```yaml
format_version: 1
name: stability
display_name: Stability AI
tier: 3
last_verified: "2026-04-05"
keywords:
- "stability"
- "STABILITY_API_KEY"
- "STABILITY_KEY"
- "api.stability.ai"
- "stable-diffusion"
patterns:
- regex: 'sk-[A-Za-z0-9]{48}'
entropy_min: 4.0
confidence: medium
verify:
method: GET
url: https://api.stability.ai/v1/user/account
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/runway.yaml:
```yaml
format_version: 1
name: runway
display_name: Runway
tier: 3
last_verified: "2026-04-05"
keywords:
- "runway"
- "runwayml"
- "RUNWAY_API_KEY"
- "RUNWAYML_API_SECRET"
- "api.runwayml.com"
- "dev.runwayml.com"
verify:
method: GET
url: https://api.dev.runwayml.com/v1/tasks
headers:
Authorization: "Bearer {KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
providers/midjourney.yaml:
```yaml
format_version: 1
name: midjourney
display_name: Midjourney
tier: 3
last_verified: "2026-04-05"
keywords:
- "midjourney"
- "MIDJOURNEY_API_KEY"
- "MJ_API_KEY"
- "midjourney.com"
- "useapi.net"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
Copy all 5 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in deepgram elevenlabs stability runway midjourney; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 10 files exist
- `grep -q 'XI_API_KEY' providers/elevenlabs.yaml`
- `grep -q 'stable-diffusion' providers/stability.yaml`
- `grep -q 'runwayml' providers/runway.yaml`
- `grep -L 'patterns:' providers/runway.yaml providers/midjourney.yaml` returns both (keyword-only)
- Total Tier 3 count: `grep -l 'tier: 3' providers/*.yaml | wc -l` → 12 (11 new + pre-existing huggingface)
- `go test ./pkg/providers/... -count=1` passes
- `go test ./pkg/engine/... -count=1` passes
</acceptance_criteria>
<done>All 11 new Tier 3 Specialized providers dual-located. PROV-03 satisfied (12 total with pre-existing huggingface).</done>
</task>
</tasks>
<verification>
`grep -l 'tier: 3' providers/*.yaml | wc -l` returns 12.
</verification>
<success_criteria>
- 11 new Tier 3 providers added (huggingface pre-existing, total 12)
- All dual-located
- Documented prefixes use tight regex; undocumented use keyword-only
- No engine regression
</success_criteria>
<output>
After completion, create `.planning/phases/03-tier-3-9-providers/03-02-SUMMARY.md`
</output>

View File

@@ -0,0 +1,393 @@
---
phase: 03-tier-3-9-providers
plan: 03
type: execute
wave: 1
depends_on: []
files_modified:
- providers/openrouter.yaml
- providers/litellm.yaml
- providers/cloudflare-ai.yaml
- providers/vercel-ai.yaml
- providers/portkey.yaml
- providers/helicone.yaml
- providers/martian.yaml
- providers/kong.yaml
- providers/bricksai.yaml
- providers/aether.yaml
- providers/notdiamond.yaml
- pkg/providers/definitions/openrouter.yaml
- pkg/providers/definitions/litellm.yaml
- pkg/providers/definitions/cloudflare-ai.yaml
- pkg/providers/definitions/vercel-ai.yaml
- pkg/providers/definitions/portkey.yaml
- pkg/providers/definitions/helicone.yaml
- pkg/providers/definitions/martian.yaml
- pkg/providers/definitions/kong.yaml
- pkg/providers/definitions/bricksai.yaml
- pkg/providers/definitions/aether.yaml
- pkg/providers/definitions/notdiamond.yaml
autonomous: true
requirements: [PROV-05]
must_haves:
truths:
- "11 Tier 5 infrastructure/gateway provider YAMLs load"
- "OpenRouter sk-or- and Helicone sk-helicone- prefixes use high-confidence regex"
- "Gateway providers have strong keyword anchors to their SDK envs"
artifacts:
- path: "providers/openrouter.yaml"
provides: "OpenRouter sk-or- prefix pattern"
contains: "sk-or-"
- path: "providers/helicone.yaml"
provides: "Helicone sk-helicone- prefix pattern"
contains: "helicone"
- path: "providers/litellm.yaml"
provides: "LiteLLM proxy keyword detection"
contains: "litellm"
key_links:
- from: "provider keywords[]"
to: "Registry Aho-Corasick automaton"
via: "NewRegistry()"
pattern: "keywords"
---
<objective>
Create 11 Tier 5 Infrastructure/Gateway provider YAMLs — LLM routers, proxies, and observability gateways (OpenRouter, LiteLLM, Cloudflare AI, Vercel AI, Portkey, Helicone, Martian, Kong, BricksAI, Aether, Not Diamond).
Purpose: Satisfy PROV-05 (11 Tier 5 Infrastructure/Gateway providers). Several of these have documented key prefixes (sk-or-, sk-helicone-) that support high-confidence detection.
Output: 22 YAML files.
Addresses PROV-05.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/03-tier-3-9-providers/03-CONTEXT.md
@pkg/providers/schema.go
@providers/groq.yaml
<interfaces>
Schema per pkg/providers/schema.go. No category field. Dual-location required. RE2 regex only.
Keyword-only detection for providers without documented key formats.
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: OpenRouter, LiteLLM, Cloudflare, Vercel, Portkey, Helicone YAMLs</name>
<files>providers/openrouter.yaml, providers/litellm.yaml, providers/cloudflare-ai.yaml, providers/vercel-ai.yaml, providers/portkey.yaml, providers/helicone.yaml, pkg/providers/definitions/openrouter.yaml, pkg/providers/definitions/litellm.yaml, pkg/providers/definitions/cloudflare-ai.yaml, pkg/providers/definitions/vercel-ai.yaml, pkg/providers/definitions/portkey.yaml, pkg/providers/definitions/helicone.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
providers/openrouter.yaml:
```yaml
format_version: 1
name: openrouter
display_name: OpenRouter
tier: 5
last_verified: "2026-04-05"
keywords:
- "openrouter"
- "OPENROUTER_API_KEY"
- "openrouter.ai"
- "sk-or-"
patterns:
- regex: 'sk-or-v1-[a-f0-9]{64}'
entropy_min: 4.0
confidence: high
- regex: 'sk-or-[A-Za-z0-9]{40,}'
entropy_min: 4.0
confidence: medium
verify:
method: GET
url: https://openrouter.ai/api/v1/auth/key
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/litellm.yaml:
```yaml
format_version: 1
name: litellm
display_name: LiteLLM Proxy
tier: 5
last_verified: "2026-04-05"
keywords:
- "litellm"
- "LITELLM_API_KEY"
- "LITELLM_MASTER_KEY"
- "LITELLM_PROXY_API_KEY"
patterns:
- regex: 'sk-[A-Za-z0-9_\-]{20,}'
entropy_min: 4.0
confidence: low
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/cloudflare-ai.yaml:
```yaml
format_version: 1
name: cloudflare-ai
display_name: Cloudflare Workers AI
tier: 5
last_verified: "2026-04-05"
keywords:
- "cloudflare"
- "workers-ai"
- "CLOUDFLARE_API_TOKEN"
- "CLOUDFLARE_ACCOUNT_ID"
- "CF_API_TOKEN"
- "api.cloudflare.com"
patterns:
- regex: '[A-Za-z0-9_\-]{40}'
entropy_min: 4.5
confidence: low
verify:
method: GET
url: https://api.cloudflare.com/client/v4/user/tokens/verify
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/vercel-ai.yaml:
```yaml
format_version: 1
name: vercel-ai
display_name: Vercel AI Gateway
tier: 5
last_verified: "2026-04-05"
keywords:
- "vercel"
- "VERCEL_AI_GATEWAY"
- "AI_GATEWAY_API_KEY"
- "vercel.ai"
- "ai-sdk"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/portkey.yaml:
```yaml
format_version: 1
name: portkey
display_name: Portkey
tier: 5
last_verified: "2026-04-05"
keywords:
- "portkey"
- "PORTKEY_API_KEY"
- "api.portkey.ai"
- "portkey-ai"
verify:
method: GET
url: https://api.portkey.ai/v1/feedback
headers:
x-portkey-api-key: "{KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
providers/helicone.yaml:
```yaml
format_version: 1
name: helicone
display_name: Helicone
tier: 5
last_verified: "2026-04-05"
keywords:
- "helicone"
- "HELICONE_API_KEY"
- "sk-helicone-"
- "api.helicone.ai"
patterns:
- regex: 'sk-helicone-[a-z0-9]{7}-[a-z0-9]{7}-[a-z0-9]{7}-[a-z0-9]{7}'
entropy_min: 3.5
confidence: high
verify:
method: GET
url: https://api.helicone.ai/v1/key/verify
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
Copy all 6 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in openrouter litellm cloudflare-ai vercel-ai portkey helicone; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 12 files exist
- `grep -q 'sk-or-v1-' providers/openrouter.yaml`
- `grep -q 'sk-helicone-' providers/helicone.yaml`
- `grep -q 'LITELLM_MASTER_KEY' providers/litellm.yaml`
- `go test ./pkg/providers/... -count=1` passes
- `go test ./pkg/engine/... -count=1` passes
</acceptance_criteria>
<done>6 major gateway providers dual-located.</done>
</task>
<task type="auto">
<name>Task 2: Martian, Kong, BricksAI, Aether, Not Diamond YAMLs</name>
<files>providers/martian.yaml, providers/kong.yaml, providers/bricksai.yaml, providers/aether.yaml, providers/notdiamond.yaml, pkg/providers/definitions/martian.yaml, pkg/providers/definitions/kong.yaml, pkg/providers/definitions/bricksai.yaml, pkg/providers/definitions/aether.yaml, pkg/providers/definitions/notdiamond.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
All 5 use keyword-only detection (no documented public key formats). Omit patterns field.
providers/martian.yaml:
```yaml
format_version: 1
name: martian
display_name: Martian (Model Router)
tier: 5
last_verified: "2026-04-05"
keywords:
- "withmartian"
- "MARTIAN_API_KEY"
- "withmartian.com"
- "martian-router"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/kong.yaml:
```yaml
format_version: 1
name: kong
display_name: Kong AI Gateway
tier: 5
last_verified: "2026-04-05"
keywords:
- "kong"
- "KONG_API_KEY"
- "kong-ai-gateway"
- "konghq.com"
- "ai-proxy"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/bricksai.yaml:
```yaml
format_version: 1
name: bricksai
display_name: BricksAI
tier: 5
last_verified: "2026-04-05"
keywords:
- "bricksai"
- "BRICKS_API_KEY"
- "trybricks.ai"
- "bricksllm"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/aether.yaml:
```yaml
format_version: 1
name: aether
display_name: Aether AI
tier: 5
last_verified: "2026-04-05"
keywords:
- "aether"
- "AETHER_API_KEY"
- "aether.ai"
- "aetherplatform"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/notdiamond.yaml:
```yaml
format_version: 1
name: notdiamond
display_name: Not Diamond
tier: 5
last_verified: "2026-04-05"
keywords:
- "notdiamond"
- "NOTDIAMOND_API_KEY"
- "not-diamond"
- "notdiamond.ai"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
Copy all 5 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in martian kong bricksai aether notdiamond; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1 && test "$(grep -l 'tier: 5' providers/*.yaml | wc -l)" = "11"</automated>
</verify>
<acceptance_criteria>
- All 10 files exist
- `grep -q 'withmartian' providers/martian.yaml`
- `grep -q 'konghq.com' providers/kong.yaml`
- All 5 omit patterns field: `grep -L 'patterns:' providers/{martian,kong,bricksai,aether,notdiamond}.yaml` returns all 5
- Total Tier 5 count = 11: `grep -l 'tier: 5' providers/*.yaml | wc -l` → 11
- `go test ./pkg/providers/... -count=1` passes
</acceptance_criteria>
<done>All 11 Tier 5 gateway providers dual-located. PROV-05 satisfied.</done>
</task>
</tasks>
<verification>
`grep -l 'tier: 5' providers/*.yaml | wc -l` returns 11.
</verification>
<success_criteria>
- 11 Tier 5 gateway providers created
- Documented prefixes use tight high-confidence regex (openrouter, helicone)
- Undocumented providers use keyword-only detection
- No engine test regressions
</success_criteria>
<output>
After completion, create `.planning/phases/03-tier-3-9-providers/03-03-SUMMARY.md`
</output>

View File

@@ -0,0 +1,382 @@
---
phase: 03-tier-3-9-providers
plan: 04
type: execute
wave: 1
depends_on: []
files_modified:
- providers/github-copilot.yaml
- providers/cursor.yaml
- providers/tabnine.yaml
- providers/codeium.yaml
- providers/sourcegraph.yaml
- providers/codewhisperer.yaml
- providers/replit-ai.yaml
- providers/codestral.yaml
- providers/watsonx.yaml
- providers/oracle-ai.yaml
- pkg/providers/definitions/github-copilot.yaml
- pkg/providers/definitions/cursor.yaml
- pkg/providers/definitions/tabnine.yaml
- pkg/providers/definitions/codeium.yaml
- pkg/providers/definitions/sourcegraph.yaml
- pkg/providers/definitions/codewhisperer.yaml
- pkg/providers/definitions/replit-ai.yaml
- pkg/providers/definitions/codestral.yaml
- pkg/providers/definitions/watsonx.yaml
- pkg/providers/definitions/oracle-ai.yaml
autonomous: true
requirements: [PROV-07]
must_haves:
truths:
- "10 Tier 7 Code/Dev Tools provider YAMLs load"
- "Sourcegraph Cody uses documented sgp_ prefix pattern"
- "GitHub Copilot uses ghu_/gho_ token patterns"
artifacts:
- path: "providers/github-copilot.yaml"
provides: "GitHub Copilot token pattern"
contains: "copilot"
- path: "providers/sourcegraph.yaml"
provides: "Sourcegraph Cody sgp_ pattern"
contains: "sgp_"
- path: "providers/codestral.yaml"
provides: "Codestral (Mistral) keyword detection"
contains: "codestral"
key_links:
- from: "provider keywords[]"
to: "Registry Aho-Corasick automaton"
via: "NewRegistry()"
pattern: "keywords"
---
<objective>
Create 10 Tier 7 Code/Dev Tools provider YAMLs — AI coding assistants and IDE plugins (GitHub Copilot, Cursor, Tabnine, Codeium, Sourcegraph Cody, Amazon CodeWhisperer, Replit AI, Codestral, IBM watsonx, Oracle AI).
Purpose: Satisfy PROV-07 (10 Tier 7 Code/Dev Tools providers).
Output: 20 YAML files.
Addresses PROV-07.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/03-tier-3-9-providers/03-CONTEXT.md
@pkg/providers/schema.go
<interfaces>
Schema per pkg/providers/schema.go. Dual-location required. RE2 regex only.
GitHub Copilot uses standard GitHub token formats (ghu_, gho_) — keyword anchoring to "copilot" disambiguates from generic GitHub tokens.
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: GitHub Copilot, Cursor, Tabnine, Codeium, Sourcegraph YAMLs</name>
<files>providers/github-copilot.yaml, providers/cursor.yaml, providers/tabnine.yaml, providers/codeium.yaml, providers/sourcegraph.yaml, pkg/providers/definitions/github-copilot.yaml, pkg/providers/definitions/cursor.yaml, pkg/providers/definitions/tabnine.yaml, pkg/providers/definitions/codeium.yaml, pkg/providers/definitions/sourcegraph.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
providers/github-copilot.yaml:
```yaml
format_version: 1
name: github-copilot
display_name: GitHub Copilot
tier: 7
last_verified: "2026-04-05"
keywords:
- "copilot"
- "github-copilot"
- "GITHUB_COPILOT_TOKEN"
- "api.githubcopilot.com"
- "copilot-internal"
patterns:
- regex: 'ghu_[A-Za-z0-9]{36}'
entropy_min: 4.0
confidence: medium
- regex: 'gho_[A-Za-z0-9]{36}'
entropy_min: 4.0
confidence: medium
verify:
method: GET
url: https://api.github.com/user
headers:
Authorization: "token {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/cursor.yaml:
```yaml
format_version: 1
name: cursor
display_name: Cursor AI
tier: 7
last_verified: "2026-04-05"
keywords:
- "cursor"
- "CURSOR_API_KEY"
- "cursor.sh"
- "cursor.com"
- "cursor-ide"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/tabnine.yaml:
```yaml
format_version: 1
name: tabnine
display_name: Tabnine
tier: 7
last_verified: "2026-04-05"
keywords:
- "tabnine"
- "TABNINE_API_KEY"
- "api.tabnine.com"
- "tabnine-pro"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/codeium.yaml:
```yaml
format_version: 1
name: codeium
display_name: Codeium (Windsurf)
tier: 7
last_verified: "2026-04-05"
keywords:
- "codeium"
- "windsurf"
- "CODEIUM_API_KEY"
- "WINDSURF_API_KEY"
- "codeium.com"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/sourcegraph.yaml:
```yaml
format_version: 1
name: sourcegraph
display_name: Sourcegraph Cody
tier: 7
last_verified: "2026-04-05"
keywords:
- "sourcegraph"
- "cody"
- "SRC_ACCESS_TOKEN"
- "SOURCEGRAPH_TOKEN"
- "sourcegraph.com"
- "sgp_"
patterns:
- regex: 'sgp_[A-Fa-f0-9]{16,}_[A-Fa-f0-9]{40}'
entropy_min: 4.0
confidence: high
- regex: 'sgp_[A-Fa-f0-9]{40}'
entropy_min: 4.0
confidence: medium
verify:
method: GET
url: https://sourcegraph.com/.api/graphql
headers:
Authorization: "token {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
Copy all 5 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in github-copilot cursor tabnine codeium sourcegraph; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 10 files exist
- `grep -q 'ghu_' providers/github-copilot.yaml`
- `grep -q 'sgp_' providers/sourcegraph.yaml`
- `grep -q 'windsurf' providers/codeium.yaml`
- `go test ./pkg/providers/... -count=1` passes
- `go test ./pkg/engine/... -count=1` passes
</acceptance_criteria>
<done>5 code assistant providers dual-located.</done>
</task>
<task type="auto">
<name>Task 2: CodeWhisperer, Replit AI, Codestral, watsonx, Oracle AI YAMLs</name>
<files>providers/codewhisperer.yaml, providers/replit-ai.yaml, providers/codestral.yaml, providers/watsonx.yaml, providers/oracle-ai.yaml, pkg/providers/definitions/codewhisperer.yaml, pkg/providers/definitions/replit-ai.yaml, pkg/providers/definitions/codestral.yaml, pkg/providers/definitions/watsonx.yaml, pkg/providers/definitions/oracle-ai.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
providers/codewhisperer.yaml:
```yaml
format_version: 1
name: codewhisperer
display_name: Amazon CodeWhisperer / Q Developer
tier: 7
last_verified: "2026-04-05"
keywords:
- "codewhisperer"
- "q-developer"
- "amazonq"
- "codewhisperer.us-east-1.amazonaws.com"
- "CODEWHISPERER_PROFILE_ARN"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/replit-ai.yaml:
```yaml
format_version: 1
name: replit-ai
display_name: Replit AI (Ghostwriter)
tier: 7
last_verified: "2026-04-05"
keywords:
- "replit"
- "ghostwriter"
- "REPLIT_TOKEN"
- "REPLIT_DB_URL"
- "replit.com"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/codestral.yaml:
```yaml
format_version: 1
name: codestral
display_name: Codestral (Mistral Code)
tier: 7
last_verified: "2026-04-05"
keywords:
- "codestral"
- "CODESTRAL_API_KEY"
- "codestral.mistral.ai"
- "codestral-latest"
patterns:
- regex: '[a-zA-Z0-9]{32}'
entropy_min: 4.5
confidence: low
verify:
method: GET
url: https://codestral.mistral.ai/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/watsonx.yaml:
```yaml
format_version: 1
name: watsonx
display_name: IBM watsonx
tier: 7
last_verified: "2026-04-05"
keywords:
- "watsonx"
- "WATSONX_API_KEY"
- "WATSONX_PROJECT_ID"
- "IBM_CLOUD_API_KEY"
- "us-south.ml.cloud.ibm.com"
- "watsonx.ai"
verify:
method: POST
url: https://iam.cloud.ibm.com/identity/token
headers: {}
valid_status: [200]
invalid_status: [400, 401]
```
providers/oracle-ai.yaml:
```yaml
format_version: 1
name: oracle-ai
display_name: Oracle Generative AI
tier: 7
last_verified: "2026-04-05"
keywords:
- "oci-genai"
- "oracle-genai"
- "OCI_GENAI"
- "generativeai.oci.oraclecloud.com"
- "oraclecloud.com"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
Copy all 5 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in codewhisperer replit-ai codestral watsonx oracle-ai; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1 && test $(grep -l 'tier: 7' providers/*.yaml | wc -l) -eq 10</automated>
</verify>
<acceptance_criteria>
- All 10 files exist
- `grep -q 'codewhisperer' providers/codewhisperer.yaml`
- `grep -q 'watsonx.ai' providers/watsonx.yaml`
- `grep -q 'oraclecloud' providers/oracle-ai.yaml`
- Total Tier 7 count = 10
- `go test ./pkg/providers/... -count=1` passes
</acceptance_criteria>
<done>All 10 Tier 7 code/dev tools providers dual-located. PROV-07 satisfied.</done>
</task>
</tasks>
<verification>
`grep -l 'tier: 7' providers/*.yaml | wc -l` returns 10.
</verification>
<success_criteria>
- 10 Tier 7 code/dev tools providers created
- Sourcegraph uses documented sgp_ high-confidence pattern
- Undocumented providers (cursor, tabnine, codeium, codewhisperer, replit-ai, oracle-ai) use keyword-only
- No engine regression
</success_criteria>
<output>
After completion, create `.planning/phases/03-tier-3-9-providers/03-04-SUMMARY.md`
</output>

View File

@@ -0,0 +1,364 @@
---
phase: 03-tier-3-9-providers
plan: 05
type: execute
wave: 1
depends_on: []
files_modified:
- providers/ollama.yaml
- providers/vllm.yaml
- providers/localai.yaml
- providers/lmstudio.yaml
- providers/llamacpp.yaml
- providers/gpt4all.yaml
- providers/text-gen-webui.yaml
- providers/tensorrt-llm.yaml
- providers/triton.yaml
- providers/jan.yaml
- pkg/providers/definitions/ollama.yaml
- pkg/providers/definitions/vllm.yaml
- pkg/providers/definitions/localai.yaml
- pkg/providers/definitions/lmstudio.yaml
- pkg/providers/definitions/llamacpp.yaml
- pkg/providers/definitions/gpt4all.yaml
- pkg/providers/definitions/text-gen-webui.yaml
- pkg/providers/definitions/tensorrt-llm.yaml
- pkg/providers/definitions/triton.yaml
- pkg/providers/definitions/jan.yaml
autonomous: true
requirements: [PROV-08]
must_haves:
truths:
- "10 Tier 8 Self-Hosted runtime provider YAMLs load"
- "Self-hosted runtimes mostly use keyword-only detection (local auth, not API keys)"
- "Runtimes exposing API key auth (vLLM --api-key, LocalAI) include env var keywords"
artifacts:
- path: "providers/ollama.yaml"
provides: "Ollama localhost endpoint keywords"
contains: "ollama"
- path: "providers/vllm.yaml"
provides: "vLLM --api-key detection keywords"
contains: "vllm"
key_links:
- from: "provider keywords[]"
to: "Registry Aho-Corasick automaton"
via: "NewRegistry()"
pattern: "keywords"
---
<objective>
Create 10 Tier 8 Self-Hosted LLM runtime provider YAMLs — local inference servers (Ollama, vLLM, LocalAI, LM Studio, llama.cpp, GPT4All, text-generation-webui, TensorRT-LLM, Triton, Jan AI).
Purpose: Satisfy PROV-08 (10 Tier 8 Self-Hosted providers). Self-hosted runtimes are interesting for OSINT (exposed endpoints via Shodan) even without API keys — keyword anchors enable later recon phases to correlate.
Output: 20 YAML files.
Addresses PROV-08.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/03-tier-3-9-providers/03-CONTEXT.md
@pkg/providers/schema.go
<interfaces>
Self-hosted runtimes rarely use bearer tokens. Detection relies on config env vars, localhost endpoints (11434, 8000, 1234), CLI flags. All use keyword-only — omit patterns entirely.
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Ollama, vLLM, LocalAI, LM Studio, llama.cpp YAMLs</name>
<files>providers/ollama.yaml, providers/vllm.yaml, providers/localai.yaml, providers/lmstudio.yaml, providers/llamacpp.yaml, pkg/providers/definitions/ollama.yaml, pkg/providers/definitions/vllm.yaml, pkg/providers/definitions/localai.yaml, pkg/providers/definitions/lmstudio.yaml, pkg/providers/definitions/llamacpp.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
All 5 use keyword-only detection — omit patterns field.
providers/ollama.yaml:
```yaml
format_version: 1
name: ollama
display_name: Ollama
tier: 8
last_verified: "2026-04-05"
keywords:
- "ollama"
- "OLLAMA_HOST"
- "OLLAMA_API_KEY"
- "OLLAMA_MODELS"
- "localhost:11434"
- "127.0.0.1:11434"
- "api/generate"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/vllm.yaml:
```yaml
format_version: 1
name: vllm
display_name: vLLM
tier: 8
last_verified: "2026-04-05"
keywords:
- "vllm"
- "VLLM_API_KEY"
- "vllm-openai"
- "--api-key"
- "openai.api_server"
- "vllm.entrypoints"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/localai.yaml:
```yaml
format_version: 1
name: localai
display_name: LocalAI
tier: 8
last_verified: "2026-04-05"
keywords:
- "localai"
- "LOCALAI_API_KEY"
- "go-skynet"
- "localai.io"
- "localhost:8080"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/lmstudio.yaml:
```yaml
format_version: 1
name: lmstudio
display_name: LM Studio
tier: 8
last_verified: "2026-04-05"
keywords:
- "lmstudio"
- "lm-studio"
- "LMSTUDIO_API_KEY"
- "localhost:1234"
- "lmstudio.ai"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/llamacpp.yaml:
```yaml
format_version: 1
name: llamacpp
display_name: llama.cpp server
tier: 8
last_verified: "2026-04-05"
keywords:
- "llama.cpp"
- "llama-cpp"
- "llama_cpp"
- "LLAMA_API_KEY"
- "ggml"
- "gguf"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
Copy all 5 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in ollama vllm localai lmstudio llamacpp; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 10 files exist
- `grep -q 'localhost:11434' providers/ollama.yaml`
- `grep -q 'vllm.entrypoints' providers/vllm.yaml`
- `grep -q 'gguf' providers/llamacpp.yaml`
- All 5 omit patterns field: `grep -L 'patterns:' providers/{ollama,vllm,localai,lmstudio,llamacpp}.yaml` returns all 5
- `go test ./pkg/providers/... -count=1` passes
</acceptance_criteria>
<done>5 self-hosted runtimes dual-located, keyword-only.</done>
</task>
<task type="auto">
<name>Task 2: GPT4All, text-gen-webui, TensorRT-LLM, Triton, Jan AI YAMLs</name>
<files>providers/gpt4all.yaml, providers/text-gen-webui.yaml, providers/tensorrt-llm.yaml, providers/triton.yaml, providers/jan.yaml, pkg/providers/definitions/gpt4all.yaml, pkg/providers/definitions/text-gen-webui.yaml, pkg/providers/definitions/tensorrt-llm.yaml, pkg/providers/definitions/triton.yaml, pkg/providers/definitions/jan.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
All keyword-only (no patterns field).
providers/gpt4all.yaml:
```yaml
format_version: 1
name: gpt4all
display_name: GPT4All
tier: 8
last_verified: "2026-04-05"
keywords:
- "gpt4all"
- "nomic-ai"
- "GPT4ALL_API_KEY"
- "gpt4all.io"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/text-gen-webui.yaml:
```yaml
format_version: 1
name: text-gen-webui
display_name: text-generation-webui (oobabooga)
tier: 8
last_verified: "2026-04-05"
keywords:
- "text-generation-webui"
- "oobabooga"
- "TEXTGEN_API_KEY"
- "text-gen-webui"
- "localhost:5000"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/tensorrt-llm.yaml:
```yaml
format_version: 1
name: tensorrt-llm
display_name: NVIDIA TensorRT-LLM
tier: 8
last_verified: "2026-04-05"
keywords:
- "tensorrt-llm"
- "trtllm"
- "TRTLLM_API_KEY"
- "tensorrt_llm"
- "nvidia-nim"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/triton.yaml:
```yaml
format_version: 1
name: triton
display_name: NVIDIA Triton Inference Server
tier: 8
last_verified: "2026-04-05"
keywords:
- "triton-inference-server"
- "tritonserver"
- "TRITON_API_KEY"
- "triton_grpc"
- "v2/models"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/jan.yaml:
```yaml
format_version: 1
name: jan
display_name: Jan AI
tier: 8
last_verified: "2026-04-05"
keywords:
- "jan-ai"
- "janhq"
- "JAN_API_KEY"
- "jan.ai"
- "cortex-cpp"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
Copy all 5 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in gpt4all text-gen-webui tensorrt-llm triton jan; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1 && test $(grep -l 'tier: 8' providers/*.yaml | wc -l) -eq 10</automated>
</verify>
<acceptance_criteria>
- All 10 files exist
- `grep -q 'oobabooga' providers/text-gen-webui.yaml`
- `grep -q 'tritonserver' providers/triton.yaml`
- `grep -q 'janhq' providers/jan.yaml`
- Total Tier 8 count = 10
- `go test ./pkg/providers/... -count=1` passes
</acceptance_criteria>
<done>All 10 Tier 8 self-hosted runtimes dual-located. PROV-08 satisfied.</done>
</task>
</tasks>
<verification>
`grep -l 'tier: 8' providers/*.yaml | wc -l` returns 10.
</verification>
<success_criteria>
- 10 Tier 8 self-hosted runtimes created
- All keyword-only (no regex patterns — avoids false positives)
- Localhost endpoints and env vars captured as keywords
- No engine regression
</success_criteria>
<output>
After completion, create `.planning/phases/03-tier-3-9-providers/03-05-SUMMARY.md`
</output>

View File

@@ -0,0 +1,331 @@
---
phase: 03-tier-3-9-providers
plan: 06
type: execute
wave: 1
depends_on: []
files_modified:
- providers/salesforce-einstein.yaml
- providers/servicenow.yaml
- providers/sap-ai-core.yaml
- providers/palantir.yaml
- providers/databricks.yaml
- providers/snowflake.yaml
- providers/oracle-genai.yaml
- providers/hpe-greenlake.yaml
- pkg/providers/definitions/salesforce-einstein.yaml
- pkg/providers/definitions/servicenow.yaml
- pkg/providers/definitions/sap-ai-core.yaml
- pkg/providers/definitions/palantir.yaml
- pkg/providers/definitions/databricks.yaml
- pkg/providers/definitions/snowflake.yaml
- pkg/providers/definitions/oracle-genai.yaml
- pkg/providers/definitions/hpe-greenlake.yaml
autonomous: true
requirements: [PROV-09]
must_haves:
truths:
- "8 Tier 9 Enterprise provider YAMLs load"
- "Databricks dapi-prefix and Snowflake JWT keywords captured"
- "All enterprise providers have strong env var keyword anchors"
artifacts:
- path: "providers/databricks.yaml"
provides: "Databricks dapi token pattern"
contains: "dapi"
- path: "providers/snowflake.yaml"
provides: "Snowflake Cortex keyword detection"
contains: "snowflake"
- path: "providers/palantir.yaml"
provides: "Palantir AIP keyword detection"
contains: "palantir"
key_links:
- from: "provider keywords[]"
to: "Registry Aho-Corasick automaton"
via: "NewRegistry()"
pattern: "keywords"
---
<objective>
Create 8 Tier 9 Enterprise AI platform provider YAMLs — enterprise SaaS AI (Salesforce Einstein, ServiceNow Now Assist, SAP Joule, Palantir AIP, Databricks, Snowflake Cortex, Oracle GenAI, HPE GreenLake).
Purpose: Satisfy PROV-09 (8 Tier 9 Enterprise providers). These target regulated enterprise estates where leaked keys carry high blast radius.
Output: 16 YAML files.
Addresses PROV-09.
Note: `oracle-genai` here is distinct from `oracle-ai` in plan 03-04 (which is Tier 7 code tools). Tier 9 entry uses name `oracle-genai` to avoid collision.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/03-tier-3-9-providers/03-CONTEXT.md
@pkg/providers/schema.go
<interfaces>
Dual-location required. Keyword-only for most; databricks has a documented `dapi` prefix.
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Salesforce, ServiceNow, SAP, Palantir YAMLs</name>
<files>providers/salesforce-einstein.yaml, providers/servicenow.yaml, providers/sap-ai-core.yaml, providers/palantir.yaml, pkg/providers/definitions/salesforce-einstein.yaml, pkg/providers/definitions/servicenow.yaml, pkg/providers/definitions/sap-ai-core.yaml, pkg/providers/definitions/palantir.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
All 4 use keyword-only detection (no public key formats documented).
providers/salesforce-einstein.yaml:
```yaml
format_version: 1
name: salesforce-einstein
display_name: Salesforce Einstein GPT
tier: 9
last_verified: "2026-04-05"
keywords:
- "einstein-gpt"
- "einsteinGPT"
- "SALESFORCE_CONSUMER_KEY"
- "SALESFORCE_CONSUMER_SECRET"
- "api.salesforce.com"
- "einstein.ai"
- "salesforce-einstein"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/servicenow.yaml:
```yaml
format_version: 1
name: servicenow
display_name: ServiceNow Now Assist
tier: 9
last_verified: "2026-04-05"
keywords:
- "servicenow"
- "now-assist"
- "SERVICENOW_INSTANCE"
- "SERVICENOW_USERNAME"
- "SERVICENOW_PASSWORD"
- "service-now.com"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/sap-ai-core.yaml:
```yaml
format_version: 1
name: sap-ai-core
display_name: SAP AI Core / Joule
tier: 9
last_verified: "2026-04-05"
keywords:
- "sap-ai-core"
- "sap-joule"
- "SAP_AICORE_CLIENT_ID"
- "SAP_AICORE_CLIENT_SECRET"
- "SAP_AICORE_AUTH_URL"
- "hana.ondemand.com"
- "aicore"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/palantir.yaml:
```yaml
format_version: 1
name: palantir
display_name: Palantir AIP
tier: 9
last_verified: "2026-04-05"
keywords:
- "palantir"
- "foundry"
- "PALANTIR_TOKEN"
- "FOUNDRY_TOKEN"
- "palantirfoundry.com"
- "aip-agents"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
Copy all 4 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in salesforce-einstein servicenow sap-ai-core palantir; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 8 files exist
- `grep -q 'einsteinGPT' providers/salesforce-einstein.yaml`
- `grep -q 'foundry' providers/palantir.yaml`
- `grep -q 'SAP_AICORE_CLIENT_ID' providers/sap-ai-core.yaml`
- `go test ./pkg/providers/... -count=1` passes
</acceptance_criteria>
<done>4 enterprise platform providers dual-located.</done>
</task>
<task type="auto">
<name>Task 2: Databricks, Snowflake, Oracle GenAI, HPE GreenLake YAMLs</name>
<files>providers/databricks.yaml, providers/snowflake.yaml, providers/oracle-genai.yaml, providers/hpe-greenlake.yaml, pkg/providers/definitions/databricks.yaml, pkg/providers/definitions/snowflake.yaml, pkg/providers/definitions/oracle-genai.yaml, pkg/providers/definitions/hpe-greenlake.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
providers/databricks.yaml:
```yaml
format_version: 1
name: databricks
display_name: Databricks (DBRX / Mosaic)
tier: 9
last_verified: "2026-04-05"
keywords:
- "databricks"
- "DATABRICKS_TOKEN"
- "DATABRICKS_HOST"
- "dbrx"
- "mosaicml"
- "dapi"
- ".cloud.databricks.com"
patterns:
- regex: 'dapi[a-f0-9]{32}(-[0-9]{1,2})?'
entropy_min: 3.5
confidence: high
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/snowflake.yaml:
```yaml
format_version: 1
name: snowflake
display_name: Snowflake Cortex
tier: 9
last_verified: "2026-04-05"
keywords:
- "snowflake"
- "SNOWFLAKE_ACCOUNT"
- "SNOWFLAKE_USER"
- "SNOWFLAKE_PASSWORD"
- "SNOWFLAKE_PRIVATE_KEY"
- "snowflakecomputing.com"
- "cortex"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/oracle-genai.yaml:
```yaml
format_version: 1
name: oracle-genai
display_name: Oracle Cloud Generative AI Service
tier: 9
last_verified: "2026-04-05"
keywords:
- "oci-generative-ai"
- "OCI_GENAI_COMPARTMENT"
- "oracle-cloud-genai"
- "inference.generativeai.us-chicago-1"
- "oci-cli"
- "OCI_CONFIG_FILE"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/hpe-greenlake.yaml:
```yaml
format_version: 1
name: hpe-greenlake
display_name: HPE GreenLake for LLMs
tier: 9
last_verified: "2026-04-05"
keywords:
- "hpe-greenlake"
- "greenlake"
- "HPE_CLIENT_ID"
- "HPE_CLIENT_SECRET"
- "common.cloud.hpe.com"
- "hpe-ai"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
Copy all 4 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in databricks snowflake oracle-genai hpe-greenlake; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1 && test $(grep -l 'tier: 9' providers/*.yaml | wc -l) -eq 8</automated>
</verify>
<acceptance_criteria>
- All 8 files exist
- `grep -q 'dapi' providers/databricks.yaml`
- `grep -q 'snowflakecomputing.com' providers/snowflake.yaml`
- `grep -q 'greenlake' providers/hpe-greenlake.yaml`
- Total Tier 9 count = 8
- `go test ./pkg/providers/... -count=1` passes
</acceptance_criteria>
<done>All 8 Tier 9 enterprise providers dual-located. PROV-09 satisfied.</done>
</task>
</tasks>
<verification>
`grep -l 'tier: 9' providers/*.yaml | wc -l` returns 8.
</verification>
<success_criteria>
- 8 Tier 9 enterprise providers created
- Databricks uses documented `dapi` high-confidence pattern
- Strong env var keyword anchors on all
- No engine regression
</success_criteria>
<output>
After completion, create `.planning/phases/03-tier-3-9-providers/03-06-SUMMARY.md`
</output>

View File

@@ -0,0 +1,504 @@
---
phase: 03-tier-3-9-providers
plan: 07
type: execute
wave: 1
depends_on: []
files_modified:
- providers/reka.yaml
- providers/aleph-alpha.yaml
- providers/writer.yaml
- providers/jasper.yaml
- providers/typeface.yaml
- providers/comet.yaml
- providers/wandb.yaml
- providers/langsmith.yaml
- providers/pinecone.yaml
- providers/weaviate.yaml
- providers/qdrant.yaml
- providers/chroma.yaml
- providers/milvus.yaml
- providers/neon.yaml
- providers/lamini.yaml
- pkg/providers/definitions/reka.yaml
- pkg/providers/definitions/aleph-alpha.yaml
- pkg/providers/definitions/writer.yaml
- pkg/providers/definitions/jasper.yaml
- pkg/providers/definitions/typeface.yaml
- pkg/providers/definitions/comet.yaml
- pkg/providers/definitions/wandb.yaml
- pkg/providers/definitions/langsmith.yaml
- pkg/providers/definitions/pinecone.yaml
- pkg/providers/definitions/weaviate.yaml
- pkg/providers/definitions/qdrant.yaml
- pkg/providers/definitions/chroma.yaml
- pkg/providers/definitions/milvus.yaml
- pkg/providers/definitions/neon.yaml
- pkg/providers/definitions/lamini.yaml
autonomous: true
requirements: [PROV-06]
must_haves:
truths:
- "15 Tier 6 Emerging/Niche provider YAMLs load"
- "W&B uses documented 40-hex key; LangSmith uses lsv2_ prefix; Pinecone uses pcsk_ prefix"
- "Vector DBs and writing tools have strong env var keyword anchors"
artifacts:
- path: "providers/langsmith.yaml"
provides: "LangSmith lsv2_ prefix pattern"
contains: "lsv2_"
- path: "providers/pinecone.yaml"
provides: "Pinecone pcsk_ prefix pattern"
contains: "pcsk_"
- path: "providers/wandb.yaml"
provides: "Weights & Biases 40-hex key pattern"
contains: "WANDB_API_KEY"
key_links:
- from: "provider keywords[]"
to: "Registry Aho-Corasick automaton"
via: "NewRegistry()"
pattern: "keywords"
---
<objective>
Create 15 Tier 6 Emerging/Niche provider YAMLs — emerging LLM labs (Reka, Aleph Alpha, Lamini), writing tools (Writer, Jasper, Typeface), observability (Comet, W&B, LangSmith), and vector DBs (Pinecone, Weaviate, Qdrant, Chroma, Milvus, Neon).
Purpose: Satisfy PROV-06 (15 Tier 6 Emerging/Niche providers).
Output: 30 YAML files.
Addresses PROV-06.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/03-tier-3-9-providers/03-CONTEXT.md
@pkg/providers/schema.go
<interfaces>
Dual-location required. Several providers in this group have documented prefixes (LangSmith lsv2_, Pinecone pcsk_, W&B 40-hex). Others use keyword-only.
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Emerging labs + writing tools (Reka, Aleph Alpha, Lamini, Writer, Jasper, Typeface, Comet, W&B)</name>
<files>providers/reka.yaml, providers/aleph-alpha.yaml, providers/lamini.yaml, providers/writer.yaml, providers/jasper.yaml, providers/typeface.yaml, providers/comet.yaml, providers/wandb.yaml, pkg/providers/definitions/reka.yaml, pkg/providers/definitions/aleph-alpha.yaml, pkg/providers/definitions/lamini.yaml, pkg/providers/definitions/writer.yaml, pkg/providers/definitions/jasper.yaml, pkg/providers/definitions/typeface.yaml, pkg/providers/definitions/comet.yaml, pkg/providers/definitions/wandb.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
providers/reka.yaml:
```yaml
format_version: 1
name: reka
display_name: Reka AI
tier: 6
last_verified: "2026-04-05"
keywords:
- "reka"
- "REKA_API_KEY"
- "api.reka.ai"
- "reka-core"
- "reka-flash"
verify:
method: GET
url: https://api.reka.ai/v1/models
headers:
X-Api-Key: "{KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/aleph-alpha.yaml:
```yaml
format_version: 1
name: aleph-alpha
display_name: Aleph Alpha
tier: 6
last_verified: "2026-04-05"
keywords:
- "aleph-alpha"
- "aleph_alpha"
- "ALEPH_ALPHA_API_KEY"
- "AA_TOKEN"
- "api.aleph-alpha.com"
- "luminous"
verify:
method: GET
url: https://api.aleph-alpha.com/models_available
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/lamini.yaml:
```yaml
format_version: 1
name: lamini
display_name: Lamini
tier: 6
last_verified: "2026-04-05"
keywords:
- "lamini"
- "LAMINI_API_KEY"
- "api.lamini.ai"
- "lamini.ai"
verify:
method: GET
url: https://api.lamini.ai/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/writer.yaml:
```yaml
format_version: 1
name: writer
display_name: Writer
tier: 6
last_verified: "2026-04-05"
keywords:
- "writer.com"
- "WRITER_API_KEY"
- "api.writer.com"
- "palmyra"
verify:
method: GET
url: https://api.writer.com/v1/models
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/jasper.yaml:
```yaml
format_version: 1
name: jasper
display_name: Jasper AI
tier: 6
last_verified: "2026-04-05"
keywords:
- "jasper.ai"
- "JASPER_API_KEY"
- "api.jasper.ai"
- "jasper-ai"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/typeface.yaml:
```yaml
format_version: 1
name: typeface
display_name: Typeface
tier: 6
last_verified: "2026-04-05"
keywords:
- "typeface"
- "typeface.ai"
- "TYPEFACE_API_KEY"
- "typeface-app"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/comet.yaml:
```yaml
format_version: 1
name: comet
display_name: Comet ML / Opik
tier: 6
last_verified: "2026-04-05"
keywords:
- "comet_ml"
- "comet-ml"
- "COMET_API_KEY"
- "COMET_WORKSPACE"
- "opik"
- "comet.com"
verify:
method: GET
url: https://www.comet.com/api/rest/v2/workspaces
headers:
Authorization: "{KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/wandb.yaml:
```yaml
format_version: 1
name: wandb
display_name: Weights & Biases
tier: 6
last_verified: "2026-04-05"
keywords:
- "wandb"
- "weights_and_biases"
- "WANDB_API_KEY"
- "api.wandb.ai"
- "wandb.ai"
patterns:
- regex: '[a-f0-9]{40}'
entropy_min: 3.5
confidence: low
verify:
method: GET
url: https://api.wandb.ai/graphql
headers:
Authorization: "Basic {KEY}"
valid_status: [200, 400]
invalid_status: [401, 403]
```
Copy all 8 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in reka aleph-alpha lamini writer jasper typeface comet wandb; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1</automated>
</verify>
<acceptance_criteria>
- All 16 files exist
- `grep -q 'luminous' providers/aleph-alpha.yaml`
- `grep -q 'palmyra' providers/writer.yaml`
- `grep -q 'WANDB_API_KEY' providers/wandb.yaml`
- `go test ./pkg/providers/... -count=1` passes
</acceptance_criteria>
<done>8 emerging/writing/observability providers dual-located.</done>
</task>
<task type="auto">
<name>Task 2: LangSmith + vector DBs (LangSmith, Pinecone, Weaviate, Qdrant, Chroma, Milvus, Neon)</name>
<files>providers/langsmith.yaml, providers/pinecone.yaml, providers/weaviate.yaml, providers/qdrant.yaml, providers/chroma.yaml, providers/milvus.yaml, providers/neon.yaml, pkg/providers/definitions/langsmith.yaml, pkg/providers/definitions/pinecone.yaml, pkg/providers/definitions/weaviate.yaml, pkg/providers/definitions/qdrant.yaml, pkg/providers/definitions/chroma.yaml, pkg/providers/definitions/milvus.yaml, pkg/providers/definitions/neon.yaml</files>
<read_first>
- pkg/providers/schema.go
</read_first>
<action>
providers/langsmith.yaml:
```yaml
format_version: 1
name: langsmith
display_name: LangSmith (LangChain)
tier: 6
last_verified: "2026-04-05"
keywords:
- "langsmith"
- "langchain"
- "LANGCHAIN_API_KEY"
- "LANGSMITH_API_KEY"
- "LANGCHAIN_TRACING_V2"
- "api.smith.langchain.com"
- "lsv2_"
patterns:
- regex: 'lsv2_(pt|sk)_[a-f0-9]{32}_[a-f0-9]{10}'
entropy_min: 4.0
confidence: high
verify:
method: GET
url: https://api.smith.langchain.com/info
headers:
X-API-Key: "{KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/pinecone.yaml:
```yaml
format_version: 1
name: pinecone
display_name: Pinecone
tier: 6
last_verified: "2026-04-05"
keywords:
- "pinecone"
- "PINECONE_API_KEY"
- "PINECONE_ENVIRONMENT"
- "api.pinecone.io"
- "pinecone.io"
- "pcsk_"
patterns:
- regex: 'pcsk_[A-Za-z0-9]{40,}'
entropy_min: 4.0
confidence: high
verify:
method: GET
url: https://api.pinecone.io/indexes
headers:
Api-Key: "{KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
providers/weaviate.yaml:
```yaml
format_version: 1
name: weaviate
display_name: Weaviate
tier: 6
last_verified: "2026-04-05"
keywords:
- "weaviate"
- "WEAVIATE_API_KEY"
- "WEAVIATE_URL"
- "weaviate.io"
- "wcs.api"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/qdrant.yaml:
```yaml
format_version: 1
name: qdrant
display_name: Qdrant
tier: 6
last_verified: "2026-04-05"
keywords:
- "qdrant"
- "QDRANT_API_KEY"
- "QDRANT_URL"
- "qdrant.tech"
- "cloud.qdrant.io"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/chroma.yaml:
```yaml
format_version: 1
name: chroma
display_name: Chroma
tier: 6
last_verified: "2026-04-05"
keywords:
- "chromadb"
- "chroma-client"
- "CHROMA_API_KEY"
- "CHROMA_HOST"
- "trychroma.com"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/milvus.yaml:
```yaml
format_version: 1
name: milvus
display_name: Milvus / Zilliz
tier: 6
last_verified: "2026-04-05"
keywords:
- "milvus"
- "zilliz"
- "ZILLIZ_API_KEY"
- "MILVUS_TOKEN"
- "zilliz.com"
- "api.cloud.zilliz.com"
verify:
method: GET
url: ""
headers: {}
valid_status: []
invalid_status: []
```
providers/neon.yaml:
```yaml
format_version: 1
name: neon
display_name: Neon (Serverless Postgres + pgvector)
tier: 6
last_verified: "2026-04-05"
keywords:
- "neon-db"
- "neondb"
- "NEON_API_KEY"
- "NEON_CONNECTION_STRING"
- "console.neon.tech"
- "pg.neon.tech"
verify:
method: GET
url: https://console.neon.tech/api/v2/projects
headers:
Authorization: "Bearer {KEY}"
valid_status: [200]
invalid_status: [401, 403]
```
Copy all 7 files verbatim to pkg/providers/definitions/.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && for f in langsmith pinecone weaviate qdrant chroma milvus neon; do diff providers/$f.yaml pkg/providers/definitions/$f.yaml || exit 1; done && go test ./pkg/providers/... -count=1 && go test ./pkg/engine/... -count=1 && test $(grep -l 'tier: 6' providers/*.yaml | wc -l) -eq 15</automated>
</verify>
<acceptance_criteria>
- All 14 files exist
- `grep -q 'lsv2_' providers/langsmith.yaml`
- `grep -q 'pcsk_' providers/pinecone.yaml`
- `grep -q 'zilliz' providers/milvus.yaml`
- Total Tier 6 count = 15
- `go test ./pkg/providers/... -count=1` passes
- `go test ./pkg/engine/... -count=1` passes
</acceptance_criteria>
<done>All 15 Tier 6 emerging/niche providers dual-located. PROV-06 satisfied.</done>
</task>
</tasks>
<verification>
`grep -l 'tier: 6' providers/*.yaml | wc -l` returns 15.
</verification>
<success_criteria>
- 15 Tier 6 providers created
- LangSmith lsv2_ and Pinecone pcsk_ use high-confidence regex
- Vector DB env vars captured
- No engine regression
</success_criteria>
<output>
After completion, create `.planning/phases/03-tier-3-9-providers/03-07-SUMMARY.md`
</output>

View File

@@ -0,0 +1,284 @@
---
phase: 03-tier-3-9-providers
plan: 08
type: execute
wave: 2
depends_on: ["03-01", "03-02", "03-03", "03-04", "03-05", "03-06", "03-07"]
files_modified:
- pkg/providers/tier39_test.go
autonomous: true
requirements: [PROV-03, PROV-04, PROV-05, PROV-06, PROV-07, PROV-08, PROV-09]
must_haves:
truths:
- "Registry loads 108 total providers (26 Tier 1-2 + 82 Tier 3-9)"
- "Per-tier counts enforced: T3=12, T4=16, T5=11, T6=15, T7=10, T8=10, T9=8"
- "All 82 Tier 3-9 provider names are known (lock set against drift)"
- "All regex patterns compile under RE2"
- "Every provider has ≥1 keyword (Aho-Corasick pre-filter requirement)"
- "Phase 2 Tier 1-2 guardrails still pass (no regression)"
artifacts:
- path: "pkg/providers/tier39_test.go"
provides: "Tier 3-9 guardrail tests"
contains: "TestTier39"
key_links:
- from: "pkg/providers/tier39_test.go"
to: "registry.NewRegistry() Stats() Get() All()"
via: "go test ./pkg/providers/..."
pattern: "NewRegistry"
---
<objective>
Create the Tier 3-9 guardrail test file `pkg/providers/tier39_test.go` that locks in exact provider counts, names, regex compilation, and keyword presence across all 82 new Tier 3-9 providers. Replicates the `tier12_test.go` pattern and serves as the regression net for all future phases.
Purpose: Satisfy all 7 Phase 3 requirements (PROV-03..PROV-09) with a single enforceable test. Any future change that drops a provider, renames one, or introduces a non-compiling regex will break this test in CI.
Output: 1 test file with 10+ test functions. Total registry provider count locked at 108.
Addresses PROV-03, PROV-04, PROV-05, PROV-06, PROV-07, PROV-08, PROV-09.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/03-tier-3-9-providers/03-CONTEXT.md
@pkg/providers/tier12_test.go
@pkg/providers/schema.go
<interfaces>
Replicate the `tier12_test.go` pattern exactly. Registry API: `NewRegistry()`, `Stats()`, `Get(name)`, `List()`.
Expected provider name sets (must match plans 03-01..03-07 exactly):
- Tier 3 (12): perplexity, you, voyage, jina, unstructured, assemblyai, deepgram, elevenlabs, stability, runway, midjourney, huggingface
- Tier 4 (16): deepseek, zhipu, moonshot, qwen, baidu, bytedance, 01ai, minimax, baichuan, stepfun, sensetime, iflytek, tencent, siliconflow, 360ai, kuaishou
- Tier 5 (11): openrouter, litellm, cloudflare-ai, vercel-ai, portkey, helicone, martian, kong, bricksai, aether, notdiamond
- Tier 6 (15): reka, aleph-alpha, lamini, writer, jasper, typeface, comet, wandb, langsmith, pinecone, weaviate, qdrant, chroma, milvus, neon
- Tier 7 (10): github-copilot, cursor, tabnine, codeium, sourcegraph, codewhisperer, replit-ai, codestral, watsonx, oracle-ai
- Tier 8 (10): ollama, vllm, localai, lmstudio, llamacpp, gpt4all, text-gen-webui, tensorrt-llm, triton, jan
- Tier 9 (8): salesforce-einstein, servicenow, sap-ai-core, palantir, databricks, snowflake, oracle-genai, hpe-greenlake
Total Tier 3-9: 82. Combined with Tier 1-2 (26): 108 total.
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Create tier39_test.go guardrail test file</name>
<files>pkg/providers/tier39_test.go</files>
<read_first>
- pkg/providers/tier12_test.go (pattern to replicate)
- pkg/providers/schema.go (Registry API)
</read_first>
<action>
Create `pkg/providers/tier39_test.go` with the following contents. The expected name slices MUST match the names in each plan's files exactly.
```go
package providers
import (
"testing"
)
// expectedTier3 lists all 12 Tier 3 Specialized provider names (PROV-03).
var expectedTier3 = []string{
"perplexity", "you", "voyage", "jina", "unstructured", "assemblyai",
"deepgram", "elevenlabs", "stability", "runway", "midjourney", "huggingface",
}
// expectedTier4 lists all 16 Tier 4 Chinese/Regional provider names (PROV-04).
var expectedTier4 = []string{
"deepseek", "zhipu", "moonshot", "qwen", "baidu", "bytedance",
"01ai", "minimax", "baichuan", "stepfun", "sensetime", "iflytek",
"tencent", "siliconflow", "360ai", "kuaishou",
}
// expectedTier5 lists all 11 Tier 5 Infrastructure/Gateway provider names (PROV-05).
var expectedTier5 = []string{
"openrouter", "litellm", "cloudflare-ai", "vercel-ai", "portkey",
"helicone", "martian", "kong", "bricksai", "aether", "notdiamond",
}
// expectedTier6 lists all 15 Tier 6 Emerging/Niche provider names (PROV-06).
var expectedTier6 = []string{
"reka", "aleph-alpha", "lamini", "writer", "jasper", "typeface",
"comet", "wandb", "langsmith", "pinecone", "weaviate", "qdrant",
"chroma", "milvus", "neon",
}
// expectedTier7 lists all 10 Tier 7 Code/Dev Tools provider names (PROV-07).
var expectedTier7 = []string{
"github-copilot", "cursor", "tabnine", "codeium", "sourcegraph",
"codewhisperer", "replit-ai", "codestral", "watsonx", "oracle-ai",
}
// expectedTier8 lists all 10 Tier 8 Self-Hosted provider names (PROV-08).
var expectedTier8 = []string{
"ollama", "vllm", "localai", "lmstudio", "llamacpp",
"gpt4all", "text-gen-webui", "tensorrt-llm", "triton", "jan",
}
// expectedTier9 lists all 8 Tier 9 Enterprise provider names (PROV-09).
var expectedTier9 = []string{
"salesforce-einstein", "servicenow", "sap-ai-core", "palantir",
"databricks", "snowflake", "oracle-genai", "hpe-greenlake",
}
func TestTier3Count(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
if got := reg.Stats().ByTier[3]; got != 12 {
t.Errorf("Tier 3 count = %d, want 12", got)
}
}
func TestTier4Count(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
if got := reg.Stats().ByTier[4]; got != 16 {
t.Errorf("Tier 4 count = %d, want 16", got)
}
}
func TestTier5Count(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
if got := reg.Stats().ByTier[5]; got != 11 {
t.Errorf("Tier 5 count = %d, want 11", got)
}
}
func TestTier6Count(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
if got := reg.Stats().ByTier[6]; got != 15 {
t.Errorf("Tier 6 count = %d, want 15", got)
}
}
func TestTier7Count(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
if got := reg.Stats().ByTier[7]; got != 10 {
t.Errorf("Tier 7 count = %d, want 10", got)
}
}
func TestTier8Count(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
if got := reg.Stats().ByTier[8]; got != 10 {
t.Errorf("Tier 8 count = %d, want 10", got)
}
}
func TestTier9Count(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
if got := reg.Stats().ByTier[9]; got != 8 {
t.Errorf("Tier 9 count = %d, want 8", got)
}
}
func TestTotalProviderCount(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
if got := reg.Stats().Total; got != 108 {
t.Errorf("Total provider count = %d, want 108", got)
}
}
func TestTier39ProviderNames(t *testing.T) {
reg, err := NewRegistry()
if err != nil {
t.Fatalf("NewRegistry failed: %v", err)
}
checks := []struct {
tier int
names []string
}{
{3, expectedTier3},
{4, expectedTier4},
{5, expectedTier5},
{6, expectedTier6},
{7, expectedTier7},
{8, expectedTier8},
{9, expectedTier9},
}
for _, c := range checks {
for _, name := range c.names {
p, ok := reg.Get(name)
if !ok {
t.Errorf("Tier %d provider %q not found in registry", c.tier, name)
continue
}
if p.Tier != c.tier {
t.Errorf("provider %q tier = %d, want %d", name, p.Tier, c.tier)
}
}
}
}
```
Note: Do NOT add package-level imports for `regexp``TestAllPatternsCompile` and `TestAllProvidersHaveKeywords` already exist in `tier12_test.go` and will exercise every provider (including Tier 3-9) once the registry loads them.
</action>
<verify>
<automated>cd /home/salva/Documents/apikey && go test ./pkg/providers/... -count=1 -v -run 'TestTier[3-9]|TestTotalProviderCount|TestTier39ProviderNames|TestAllPatternsCompile|TestAllProvidersHaveKeywords' && go test ./... -count=1</automated>
</verify>
<acceptance_criteria>
- `pkg/providers/tier39_test.go` exists
- `grep -c "^func Test" pkg/providers/tier39_test.go` returns ≥ 9
- `go test ./pkg/providers/... -run TestTotalProviderCount -v` passes with Total == 108
- `go test ./pkg/providers/... -run TestTier3Count -v` passes
- `go test ./pkg/providers/... -run TestTier4Count -v` passes
- `go test ./pkg/providers/... -run TestTier5Count -v` passes
- `go test ./pkg/providers/... -run TestTier6Count -v` passes
- `go test ./pkg/providers/... -run TestTier7Count -v` passes
- `go test ./pkg/providers/... -run TestTier8Count -v` passes
- `go test ./pkg/providers/... -run TestTier9Count -v` passes
- `go test ./pkg/providers/... -run TestTier39ProviderNames -v` passes (all 82 names resolve)
- `go test ./pkg/providers/... -run TestAllPatternsCompile -v` passes (inherited from tier12_test.go — all Tier 3-9 regexes compile under RE2)
- `go test ./pkg/providers/... -run TestAllProvidersHaveKeywords -v` passes (every provider ≥1 keyword)
- Phase 2 guardrails still pass: `go test ./pkg/providers/... -run 'TestTier1|TestTier2'` green
- Full repo regression: `go test ./... -count=1` green (engine, storage, providers)
</acceptance_criteria>
<done>Tier 3-9 guardrail test file exists, 9+ test functions pass, total provider count locked at 108, all 82 Tier 3-9 provider names verified, no regression in Phase 1/2 tests.</done>
</task>
</tasks>
<verification>
`go test ./... -count=1` passes. `go run . providers stats` shows Total 108, with Tier 1: 12, Tier 2: 14, Tier 3: 12, Tier 4: 16, Tier 5: 11, Tier 6: 15, Tier 7: 10, Tier 8: 10, Tier 9: 8.
</verification>
<success_criteria>
- tier39_test.go created with ≥9 test functions
- Total provider count locked at 108
- All 82 Tier 3-9 provider names locked against drift
- All regex patterns compile under RE2 (via existing TestAllPatternsCompile)
- Every provider has ≥1 keyword (via existing TestAllProvidersHaveKeywords)
- Full repo `go test ./...` green
</success_criteria>
<output>
After completion, create `.planning/phases/03-tier-3-9-providers/03-08-SUMMARY.md`
</output>