Add AI providers, lean methodologies, and WWS skills
- Add synthetic.new skill (primary AI provider) - Add z.ai skill (fallback with GLM models) - Add lean backlog management skill with WSJF prioritization - Add lean prioritization skill with scheduling/parallelization - Add WWS serverless architecture overview 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
205
skills/ai-providers/synthetic-new.md
Normal file
205
skills/ai-providers/synthetic-new.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# Skill: AI Provider - synthetic.new
|
||||
|
||||
## Description
|
||||
Primary AI provider for the Mylder platform. OpenAI-compatible API with access to DeepSeek, Kimi, and other high-performance models.
|
||||
|
||||
## Status
|
||||
**PRIMARY** - Use for all AI tasks unless fallback needed.
|
||||
|
||||
## Configuration
|
||||
```yaml
|
||||
provider: synthetic.new
|
||||
base_url: https://api.synthetic.new/openai/v1
|
||||
api_key_env: SYNTHETIC_AI_API_KEY
|
||||
compatibility: openai
|
||||
rate_limit: 100 requests/minute
|
||||
```
|
||||
|
||||
## Available Models
|
||||
|
||||
### DeepSeek-V3 (Coding & Implementation)
|
||||
```json
|
||||
{
|
||||
"model_id": "hf:deepseek-ai/DeepSeek-V3",
|
||||
"best_for": ["code_generation", "implementation", "debugging", "refactoring"],
|
||||
"context_window": 128000,
|
||||
"max_output": 8192,
|
||||
"temperature_range": [0.0, 2.0],
|
||||
"recommended_temp": 0.3
|
||||
}
|
||||
```
|
||||
|
||||
**Use when:**
|
||||
- Writing production code
|
||||
- Debugging issues
|
||||
- Code refactoring
|
||||
- API implementation
|
||||
- Database queries
|
||||
|
||||
### Kimi-K2-Thinking (Planning & Reasoning)
|
||||
```json
|
||||
{
|
||||
"model_id": "hf:moonshotai/Kimi-K2-Thinking",
|
||||
"best_for": ["planning", "reasoning", "analysis", "architecture"],
|
||||
"context_window": 200000,
|
||||
"max_output": 4096,
|
||||
"temperature_range": [0.0, 1.0],
|
||||
"recommended_temp": 0.5
|
||||
}
|
||||
```
|
||||
|
||||
**Use when:**
|
||||
- Task planning
|
||||
- Architecture decisions
|
||||
- Complex reasoning
|
||||
- Research synthesis
|
||||
- Trade-off analysis
|
||||
|
||||
## Model Selection Logic
|
||||
```javascript
|
||||
function selectModel(taskType, complexity) {
|
||||
const modelMap = {
|
||||
// Planning & Design
|
||||
'research': 'hf:moonshotai/Kimi-K2-Thinking',
|
||||
'planning': 'hf:moonshotai/Kimi-K2-Thinking',
|
||||
'architecture': 'hf:moonshotai/Kimi-K2-Thinking',
|
||||
'analysis': 'hf:moonshotai/Kimi-K2-Thinking',
|
||||
|
||||
// Implementation
|
||||
'code': 'hf:deepseek-ai/DeepSeek-V3',
|
||||
'implementation': 'hf:deepseek-ai/DeepSeek-V3',
|
||||
'debugging': 'hf:deepseek-ai/DeepSeek-V3',
|
||||
'testing': 'hf:deepseek-ai/DeepSeek-V3',
|
||||
'review': 'hf:deepseek-ai/DeepSeek-V3',
|
||||
|
||||
// Default
|
||||
'default': 'hf:deepseek-ai/DeepSeek-V3'
|
||||
};
|
||||
|
||||
return modelMap[taskType] || modelMap.default;
|
||||
}
|
||||
```
|
||||
|
||||
## n8n Integration
|
||||
|
||||
### HTTP Request Node Configuration
|
||||
```json
|
||||
{
|
||||
"method": "POST",
|
||||
"url": "https://api.synthetic.new/openai/v1/chat/completions",
|
||||
"headers": {
|
||||
"Authorization": "Bearer {{ $env.SYNTHETIC_AI_API_KEY }}",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"model": "hf:deepseek-ai/DeepSeek-V3",
|
||||
"messages": [
|
||||
{ "role": "system", "content": "{{ systemPrompt }}" },
|
||||
{ "role": "user", "content": "{{ userPrompt }}" }
|
||||
],
|
||||
"max_tokens": 4000,
|
||||
"temperature": 0.7
|
||||
},
|
||||
"timeout": 120000
|
||||
}
|
||||
```
|
||||
|
||||
### Code Node Helper
|
||||
```javascript
|
||||
// AI Request Helper for n8n Code Node
|
||||
async function callSyntheticAI(systemPrompt, userPrompt, options = {}) {
|
||||
const {
|
||||
model = 'hf:deepseek-ai/DeepSeek-V3',
|
||||
maxTokens = 4000,
|
||||
temperature = 0.7
|
||||
} = options;
|
||||
|
||||
const response = await $http.request({
|
||||
method: 'POST',
|
||||
url: 'https://api.synthetic.new/openai/v1/chat/completions',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${$env.SYNTHETIC_AI_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: {
|
||||
model,
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: userPrompt }
|
||||
],
|
||||
max_tokens: maxTokens,
|
||||
temperature
|
||||
}
|
||||
});
|
||||
|
||||
return response.choices[0].message.content;
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Retry Strategy
|
||||
```javascript
|
||||
const retryConfig = {
|
||||
maxRetries: 3,
|
||||
retryDelay: 1000, // ms
|
||||
retryOn: [429, 500, 502, 503, 504],
|
||||
fallbackProvider: 'z.ai' // Switch to fallback after max retries
|
||||
};
|
||||
```
|
||||
|
||||
### Common Errors
|
||||
| Error Code | Cause | Action |
|
||||
|------------|-------|--------|
|
||||
| 401 | Invalid API key | Check SYNTHETIC_AI_API_KEY |
|
||||
| 429 | Rate limit | Retry with backoff or fallback to z.ai |
|
||||
| 500 | Server error | Retry or fallback |
|
||||
| Timeout | Long response | Increase timeout or reduce max_tokens |
|
||||
|
||||
## Cost Optimization
|
||||
|
||||
### Token Estimation
|
||||
```javascript
|
||||
// Rough estimate: 1 token ≈ 4 characters
|
||||
function estimateTokens(text) {
|
||||
return Math.ceil(text.length / 4);
|
||||
}
|
||||
|
||||
// Budget check before request
|
||||
function checkBudget(input, maxOutput, budgetTokens) {
|
||||
const inputTokens = estimateTokens(input);
|
||||
const totalEstimate = inputTokens + maxOutput;
|
||||
return totalEstimate <= budgetTokens;
|
||||
}
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
1. **Use appropriate model** - Kimi for reasoning, DeepSeek for coding
|
||||
2. **Set max_tokens wisely** - Don't over-allocate
|
||||
3. **Cache common responses** - Use KV store for repeated queries
|
||||
4. **Batch similar requests** - Group related tasks
|
||||
|
||||
## Testing
|
||||
```bash
|
||||
# Test API connection
|
||||
curl -X POST https://api.synthetic.new/openai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $SYNTHETIC_AI_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "hf:deepseek-ai/DeepSeek-V3",
|
||||
"messages": [{"role": "user", "content": "Hello"}],
|
||||
"max_tokens": 50
|
||||
}'
|
||||
```
|
||||
|
||||
## Related Skills
|
||||
- `ai-providers/z-ai.md` - Fallback provider
|
||||
- `code/implement.md` - Code generation with AI
|
||||
- `design-thinking/ideate.md` - Solution brainstorming
|
||||
|
||||
## Token Budget
|
||||
- Max input: 500 tokens
|
||||
- Max output: 800 tokens
|
||||
|
||||
## Model
|
||||
- Recommended: haiku (configuration lookup)
|
||||
261
skills/ai-providers/z-ai.md
Normal file
261
skills/ai-providers/z-ai.md
Normal file
@@ -0,0 +1,261 @@
|
||||
# Skill: AI Provider - z.ai
|
||||
|
||||
## Description
|
||||
Fallback AI provider with GLM (General Language Model) support. Use when synthetic.new is unavailable or when GLM models are superior for specific tasks.
|
||||
|
||||
## Status
|
||||
**FALLBACK** - Use when:
|
||||
1. synthetic.new rate limits or errors
|
||||
2. GLM models outperform alternatives for the task
|
||||
3. New models available earlier on z.ai
|
||||
|
||||
## Configuration
|
||||
```yaml
|
||||
provider: z.ai
|
||||
base_url: https://api.z.ai/v1
|
||||
api_key_env: Z_AI_API_KEY
|
||||
compatibility: openai
|
||||
rate_limit: 60 requests/minute
|
||||
```
|
||||
|
||||
**Note:** API key needs to be configured. Check z.ai dashboard for key generation.
|
||||
|
||||
## Available Models
|
||||
|
||||
### GLM-4-Plus (Reasoning & Analysis)
|
||||
```json
|
||||
{
|
||||
"model_id": "glm-4-plus",
|
||||
"best_for": ["reasoning", "analysis", "chinese_language", "long_context"],
|
||||
"context_window": 128000,
|
||||
"max_output": 4096,
|
||||
"temperature_range": [0.0, 1.0],
|
||||
"recommended_temp": 0.5,
|
||||
"strengths": ["Chinese content", "Logical reasoning", "Long documents"]
|
||||
}
|
||||
```
|
||||
|
||||
**Use when:**
|
||||
- Complex logical reasoning
|
||||
- Chinese language content
|
||||
- Long document analysis
|
||||
- Comparative analysis
|
||||
|
||||
### GLM-4-Flash (Fast Responses)
|
||||
```json
|
||||
{
|
||||
"model_id": "glm-4-flash",
|
||||
"best_for": ["quick_responses", "simple_tasks", "high_volume"],
|
||||
"context_window": 32000,
|
||||
"max_output": 2048,
|
||||
"temperature_range": [0.0, 1.0],
|
||||
"recommended_temp": 0.3,
|
||||
"strengths": ["Speed", "Cost efficiency", "Simple tasks"]
|
||||
}
|
||||
```
|
||||
|
||||
**Use when:**
|
||||
- Quick classification
|
||||
- Simple transformations
|
||||
- High-volume processing
|
||||
- Cost-sensitive operations
|
||||
|
||||
### GLM-4-Long (Extended Context)
|
||||
```json
|
||||
{
|
||||
"model_id": "glm-4-long",
|
||||
"best_for": ["long_documents", "codebase_analysis", "summarization"],
|
||||
"context_window": 1000000,
|
||||
"max_output": 4096,
|
||||
"temperature_range": [0.0, 1.0],
|
||||
"recommended_temp": 0.3,
|
||||
"strengths": ["1M token context", "Document processing", "Code analysis"]
|
||||
}
|
||||
```
|
||||
|
||||
**Use when:**
|
||||
- Entire codebase analysis
|
||||
- Long document summarization
|
||||
- Multi-file code review
|
||||
|
||||
## Model Selection Logic
|
||||
```javascript
|
||||
function selectZAIModel(taskType, contextLength) {
|
||||
// Context-based selection
|
||||
if (contextLength > 128000) {
|
||||
return 'glm-4-long';
|
||||
}
|
||||
|
||||
const modelMap = {
|
||||
// Fast operations
|
||||
'classification': 'glm-4-flash',
|
||||
'extraction': 'glm-4-flash',
|
||||
'simple_qa': 'glm-4-flash',
|
||||
|
||||
// Complex reasoning
|
||||
'reasoning': 'glm-4-plus',
|
||||
'analysis': 'glm-4-plus',
|
||||
'planning': 'glm-4-plus',
|
||||
|
||||
// Long context
|
||||
'codebase': 'glm-4-long',
|
||||
'summarization': 'glm-4-long',
|
||||
|
||||
// Default
|
||||
'default': 'glm-4-plus'
|
||||
};
|
||||
|
||||
return modelMap[taskType] || modelMap.default;
|
||||
}
|
||||
```
|
||||
|
||||
## Fallback Logic
|
||||
|
||||
### When to Fallback from synthetic.new
|
||||
```javascript
|
||||
async function callWithFallback(systemPrompt, userPrompt, options = {}) {
|
||||
const primaryResult = await callSyntheticAI(systemPrompt, userPrompt, options);
|
||||
|
||||
// Check for fallback conditions
|
||||
if (primaryResult.error) {
|
||||
const errorCode = primaryResult.error.code;
|
||||
|
||||
// Rate limit or server error - fallback to z.ai
|
||||
if ([429, 500, 502, 503, 504].includes(errorCode)) {
|
||||
console.log('Falling back to z.ai');
|
||||
return await callZAI(systemPrompt, userPrompt, options);
|
||||
}
|
||||
}
|
||||
|
||||
return primaryResult;
|
||||
}
|
||||
```
|
||||
|
||||
### GLM Superiority Conditions
|
||||
```javascript
|
||||
function shouldPreferGLM(task) {
|
||||
const glmSuperiorTasks = [
|
||||
'chinese_translation',
|
||||
'chinese_content',
|
||||
'million_token_context',
|
||||
'cost_optimization',
|
||||
'new_model_testing'
|
||||
];
|
||||
|
||||
return glmSuperiorTasks.includes(task.type);
|
||||
}
|
||||
```
|
||||
|
||||
## n8n Integration
|
||||
|
||||
### HTTP Request Node Configuration
|
||||
```json
|
||||
{
|
||||
"method": "POST",
|
||||
"url": "https://api.z.ai/v1/chat/completions",
|
||||
"headers": {
|
||||
"Authorization": "Bearer {{ $env.Z_AI_API_KEY }}",
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"body": {
|
||||
"model": "glm-4-plus",
|
||||
"messages": [
|
||||
{ "role": "system", "content": "{{ systemPrompt }}" },
|
||||
{ "role": "user", "content": "{{ userPrompt }}" }
|
||||
],
|
||||
"max_tokens": 4000,
|
||||
"temperature": 0.5
|
||||
},
|
||||
"timeout": 90000
|
||||
}
|
||||
```
|
||||
|
||||
### Code Node Helper
|
||||
```javascript
|
||||
// z.ai Request Helper for n8n Code Node
|
||||
async function callZAI(systemPrompt, userPrompt, options = {}) {
|
||||
const {
|
||||
model = 'glm-4-plus',
|
||||
maxTokens = 4000,
|
||||
temperature = 0.5
|
||||
} = options;
|
||||
|
||||
const response = await $http.request({
|
||||
method: 'POST',
|
||||
url: 'https://api.z.ai/v1/chat/completions',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${$env.Z_AI_API_KEY}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: {
|
||||
model,
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: userPrompt }
|
||||
],
|
||||
max_tokens: maxTokens,
|
||||
temperature
|
||||
}
|
||||
});
|
||||
|
||||
return response.choices[0].message.content;
|
||||
}
|
||||
```
|
||||
|
||||
## Comparison: synthetic.new vs z.ai
|
||||
|
||||
| Feature | synthetic.new | z.ai |
|
||||
|---------|---------------|------|
|
||||
| Primary Use | All tasks | Fallback + GLM tasks |
|
||||
| Best Model (Code) | DeepSeek-V3 | GLM-4-Flash |
|
||||
| Best Model (Reasoning) | Kimi-K2-Thinking | GLM-4-Plus |
|
||||
| Max Context | 200K | 1M (GLM-4-Long) |
|
||||
| Chinese Support | Good | Excellent |
|
||||
| Rate Limit | 100/min | 60/min |
|
||||
| Cost | Standard | Lower (Flash) |
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Get API Key
|
||||
1. Visit https://z.ai/dashboard
|
||||
2. Create account or login
|
||||
3. Navigate to API Keys
|
||||
4. Generate new key
|
||||
5. Store as `Z_AI_API_KEY` environment variable
|
||||
|
||||
### 2. Configure in Coolify
|
||||
```bash
|
||||
# Add to service environment variables
|
||||
Z_AI_API_KEY=your_key_here
|
||||
```
|
||||
|
||||
### 3. Test Connection
|
||||
```bash
|
||||
curl -X POST https://api.z.ai/v1/chat/completions \
|
||||
-H "Authorization: Bearer $Z_AI_API_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"model": "glm-4-flash",
|
||||
"messages": [{"role": "user", "content": "Hello"}],
|
||||
"max_tokens": 50
|
||||
}'
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
| Error Code | Cause | Action |
|
||||
|------------|-------|--------|
|
||||
| 401 | Invalid API key | Check Z_AI_API_KEY |
|
||||
| 429 | Rate limit | Wait and retry |
|
||||
| 400 | Invalid model | Check model name |
|
||||
|
||||
## Related Skills
|
||||
- `ai-providers/synthetic-new.md` - Primary provider
|
||||
- `code/implement.md` - Code generation
|
||||
- `design-thinking/ideate.md` - Solution brainstorming
|
||||
|
||||
## Token Budget
|
||||
- Max input: 500 tokens
|
||||
- Max output: 800 tokens
|
||||
|
||||
## Model
|
||||
- Recommended: haiku (configuration lookup)
|
||||
251
skills/lean/backlog.md
Normal file
251
skills/lean/backlog.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Skill: Lean - Backlog Management
|
||||
|
||||
## Description
|
||||
Manage and prioritize product backlog using WSJF (Weighted Shortest Job First) and lean principles for optimal value delivery.
|
||||
|
||||
## Input
|
||||
- **project_id**: Project identifier (required)
|
||||
- **action**: list|add|prioritize|groom|estimate (required)
|
||||
- **item**: Backlog item details for add/update (optional)
|
||||
- **filters**: Status, phase, assignee filters (optional)
|
||||
|
||||
## Backlog Item Structure
|
||||
```json
|
||||
{
|
||||
"id": "BLI-042",
|
||||
"title": "Add dark mode toggle",
|
||||
"description": "Allow users to switch between light and dark themes",
|
||||
"type": "feature|bug|tech_debt|spike",
|
||||
"phase": "empathize|define|ideate|prototype|test",
|
||||
"status": "idea|ready|in_progress|review|done|blocked",
|
||||
"priority_score": 8.5,
|
||||
"scoring": {
|
||||
"user_value": 7,
|
||||
"time_criticality": 3,
|
||||
"risk_reduction": 2,
|
||||
"effort": 3
|
||||
},
|
||||
"story_points": 5,
|
||||
"assigned_agent": "frontend|backend|tester|devops|pm",
|
||||
"dependencies": ["BLI-040", "BLI-041"],
|
||||
"labels": ["ux", "settings", "mvp"],
|
||||
"acceptance_criteria": [
|
||||
"Toggle visible in settings page",
|
||||
"Theme persists across sessions",
|
||||
"Respects system preference by default"
|
||||
],
|
||||
"created_at": "2024-12-14T10:00:00Z",
|
||||
"updated_at": "2024-12-14T15:30:00Z",
|
||||
"sprint_id": null
|
||||
}
|
||||
```
|
||||
|
||||
## WSJF Prioritization
|
||||
|
||||
### Formula
|
||||
```
|
||||
Priority Score = (User Value + Time Criticality + Risk Reduction) / Effort
|
||||
|
||||
Scale: 1-10 for each factor
|
||||
Result: Higher score = Higher priority
|
||||
```
|
||||
|
||||
### Scoring Guide
|
||||
|
||||
**User Value (1-10):**
|
||||
- 10: Core feature, all users need
|
||||
- 7-9: Important feature, most users benefit
|
||||
- 4-6: Nice to have, some users want
|
||||
- 1-3: Edge case, few users affected
|
||||
|
||||
**Time Criticality (1-10):**
|
||||
- 10: Must ship this sprint, blocking release
|
||||
- 7-9: Needed soon, customer commitment
|
||||
- 4-6: Planned for quarter, flexible timing
|
||||
- 1-3: Backlog, no deadline
|
||||
|
||||
**Risk Reduction (1-10):**
|
||||
- 10: Eliminates critical security/stability risk
|
||||
- 7-9: Reduces significant technical debt
|
||||
- 4-6: Improves maintainability
|
||||
- 1-3: Minor improvement
|
||||
|
||||
**Effort (1-10):**
|
||||
- 1-2: Trivial, < 2 hours
|
||||
- 3-4: Small, 2-8 hours
|
||||
- 5-6: Medium, 1-2 days
|
||||
- 7-8: Large, 3-5 days
|
||||
- 9-10: Epic, > 1 week (should be split)
|
||||
|
||||
### Priority Buckets
|
||||
```
|
||||
Score > 10: 🔥 Critical - Do immediately
|
||||
Score 7-10: ⚡ High - Sprint commitment
|
||||
Score 4-7: 📌 Medium - Plan for next sprint
|
||||
Score < 4: 💤 Low - Future backlog
|
||||
```
|
||||
|
||||
## Backlog Actions
|
||||
|
||||
### List Backlog
|
||||
```json
|
||||
{
|
||||
"action": "list",
|
||||
"filters": {
|
||||
"status": ["ready", "in_progress"],
|
||||
"phase": "prototype",
|
||||
"label": "mvp"
|
||||
},
|
||||
"sort": "priority_score",
|
||||
"limit": 20
|
||||
}
|
||||
```
|
||||
|
||||
### Add Item
|
||||
```json
|
||||
{
|
||||
"action": "add",
|
||||
"item": {
|
||||
"title": "Implement password reset flow",
|
||||
"description": "Users need ability to reset forgotten passwords",
|
||||
"type": "feature",
|
||||
"phase": "prototype",
|
||||
"labels": ["auth", "mvp"],
|
||||
"acceptance_criteria": [
|
||||
"Email sent with reset link",
|
||||
"Link expires after 1 hour",
|
||||
"Password requirements enforced"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Prioritize Backlog
|
||||
```json
|
||||
{
|
||||
"action": "prioritize",
|
||||
"items": [
|
||||
{ "id": "BLI-042", "user_value": 7, "time_criticality": 3, "risk_reduction": 2, "effort": 3 },
|
||||
{ "id": "BLI-043", "user_value": 9, "time_criticality": 8, "risk_reduction": 5, "effort": 5 }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Groom Items
|
||||
```json
|
||||
{
|
||||
"action": "groom",
|
||||
"item_id": "BLI-042",
|
||||
"updates": {
|
||||
"description": "Updated description with more detail",
|
||||
"acceptance_criteria": ["New criteria"],
|
||||
"story_points": 8,
|
||||
"status": "ready"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Output Format
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"action": "list",
|
||||
"backlog": {
|
||||
"total_items": 45,
|
||||
"ready_items": 12,
|
||||
"in_progress": 5,
|
||||
"blocked": 1
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"id": "BLI-043",
|
||||
"title": "User authentication",
|
||||
"priority_score": 7.33,
|
||||
"status": "ready",
|
||||
"story_points": 8,
|
||||
"phase": "prototype"
|
||||
}
|
||||
],
|
||||
"recommendations": [
|
||||
{
|
||||
"type": "split",
|
||||
"item_id": "BLI-050",
|
||||
"reason": "Effort score 9 - consider breaking into smaller items"
|
||||
},
|
||||
{
|
||||
"type": "prioritize",
|
||||
"item_id": "BLI-043",
|
||||
"reason": "High time criticality, move to top"
|
||||
}
|
||||
],
|
||||
"next_step": "Plan sprint with /sprint plan"
|
||||
}
|
||||
```
|
||||
|
||||
## AI Advisory
|
||||
|
||||
### Recommendations Engine
|
||||
```javascript
|
||||
function generateRecommendations(backlog) {
|
||||
const recommendations = [];
|
||||
|
||||
// Large items should be split
|
||||
backlog.filter(i => i.scoring.effort >= 8).forEach(item => {
|
||||
recommendations.push({
|
||||
type: 'split',
|
||||
item_id: item.id,
|
||||
reason: `Effort ${item.scoring.effort} is too high. Split into 2-3 smaller items.`,
|
||||
priority: 'high'
|
||||
});
|
||||
});
|
||||
|
||||
// Blocked items need attention
|
||||
backlog.filter(i => i.status === 'blocked').forEach(item => {
|
||||
recommendations.push({
|
||||
type: 'unblock',
|
||||
item_id: item.id,
|
||||
reason: `Item blocked. Check dependencies: ${item.dependencies.join(', ')}`,
|
||||
priority: 'critical'
|
||||
});
|
||||
});
|
||||
|
||||
// Old items in "idea" status
|
||||
const oldIdeas = backlog.filter(i =>
|
||||
i.status === 'idea' &&
|
||||
daysSince(i.created_at) > 30
|
||||
);
|
||||
if (oldIdeas.length > 5) {
|
||||
recommendations.push({
|
||||
type: 'cleanup',
|
||||
reason: `${oldIdeas.length} items in "idea" status for 30+ days. Review or remove.`,
|
||||
priority: 'medium'
|
||||
});
|
||||
}
|
||||
|
||||
return recommendations;
|
||||
}
|
||||
```
|
||||
|
||||
## Quality Gates
|
||||
- [ ] All items have clear titles
|
||||
- [ ] Ready items have acceptance criteria
|
||||
- [ ] WSJF scores calculated
|
||||
- [ ] Dependencies documented
|
||||
- [ ] Large items flagged for splitting
|
||||
- [ ] Blocked items have resolution plan
|
||||
|
||||
## Token Budget
|
||||
- Max input: 800 tokens
|
||||
- Max output: 1500 tokens
|
||||
|
||||
## Model
|
||||
- Recommended: sonnet (prioritization reasoning)
|
||||
|
||||
## Philosophy
|
||||
> "Build less, ship faster. Priority is about saying no."
|
||||
|
||||
**Keep it simple:**
|
||||
- Small items > Large epics
|
||||
- Done > Perfect
|
||||
- User value > Technical elegance
|
||||
- Weekly grooming beats quarterly planning
|
||||
249
skills/lean/prioritization.md
Normal file
249
skills/lean/prioritization.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# Skill: Lean - Prioritization
|
||||
|
||||
## Description
|
||||
Apply lean prioritization frameworks to make decisions about what to build next. Uses WSJF, MoSCoW, and effort/impact matrices.
|
||||
|
||||
## Input
|
||||
- **items**: List of items to prioritize (required)
|
||||
- **framework**: wsjf|moscow|effort_impact|rice (optional, default: wsjf)
|
||||
- **constraints**: Time, budget, capacity limits (optional)
|
||||
- **weights**: Custom weights for scoring factors (optional)
|
||||
|
||||
## Prioritization Frameworks
|
||||
|
||||
### 1. WSJF (Weighted Shortest Job First)
|
||||
**Best for:** Sprint planning, feature prioritization
|
||||
|
||||
```
|
||||
Priority = (User Value + Time Criticality + Risk Reduction) / Job Size
|
||||
|
||||
Higher score = Do first
|
||||
```
|
||||
|
||||
**Scoring Matrix:**
|
||||
| Factor | 1-3 | 4-6 | 7-9 | 10 |
|
||||
|--------|-----|-----|-----|-----|
|
||||
| User Value | Few users | Some users | Most users | All users |
|
||||
| Time Criticality | No deadline | Quarter | Month | This sprint |
|
||||
| Risk Reduction | Minor | Moderate | Significant | Critical |
|
||||
| Job Size (effort) | < 2 hours | 1-2 days | 3-5 days | > 1 week |
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"item": "Add password reset",
|
||||
"user_value": 8,
|
||||
"time_criticality": 7,
|
||||
"risk_reduction": 6,
|
||||
"job_size": 5,
|
||||
"wsjf_score": 4.2
|
||||
}
|
||||
// Score = (8 + 7 + 6) / 5 = 4.2
|
||||
```
|
||||
|
||||
### 2. MoSCoW Method
|
||||
**Best for:** Release planning, MVP definition
|
||||
|
||||
| Category | Description | Guidance |
|
||||
|----------|-------------|----------|
|
||||
| **M**ust Have | Non-negotiable, core functionality | Release blocked without |
|
||||
| **S**hould Have | Important but not critical | Include if time permits |
|
||||
| **C**ould Have | Nice to have | Descope first if needed |
|
||||
| **W**on't Have | Out of scope for this release | Document for future |
|
||||
|
||||
**Distribution Rule:**
|
||||
- Must: 60% of effort
|
||||
- Should: 20% of effort
|
||||
- Could: 20% of effort
|
||||
- Won't: 0% (explicitly excluded)
|
||||
|
||||
### 3. Effort/Impact Matrix
|
||||
**Best for:** Quick prioritization, team discussions
|
||||
|
||||
```
|
||||
High Impact
|
||||
│
|
||||
Quick Wins │ Major Projects
|
||||
(Do Now) │ (Plan Carefully)
|
||||
─────────────────┼─────────────────────
|
||||
Fill-Ins │ Thankless Tasks
|
||||
(If Time) │ (Avoid/Delegate)
|
||||
│
|
||||
Low Impact
|
||||
|
||||
Low Effort ─────────────── High Effort
|
||||
```
|
||||
|
||||
**Quadrant Actions:**
|
||||
1. **Quick Wins** (High Impact, Low Effort): Do immediately
|
||||
2. **Major Projects** (High Impact, High Effort): Schedule, break down
|
||||
3. **Fill-Ins** (Low Impact, Low Effort): Do when free
|
||||
4. **Thankless Tasks** (Low Impact, High Effort): Eliminate or defer
|
||||
|
||||
### 4. RICE Framework
|
||||
**Best for:** Product decisions with reach data
|
||||
|
||||
```
|
||||
RICE Score = (Reach × Impact × Confidence) / Effort
|
||||
|
||||
Reach: Users affected per quarter
|
||||
Impact: 0.25 (minimal) to 3 (massive)
|
||||
Confidence: 0-100%
|
||||
Effort: Person-months
|
||||
```
|
||||
|
||||
## Scheduling & Parallelization
|
||||
|
||||
### Dependency Resolution
|
||||
```json
|
||||
{
|
||||
"item_id": "BLI-050",
|
||||
"depends_on": ["BLI-048", "BLI-049"],
|
||||
"blocks": ["BLI-053", "BLI-054"],
|
||||
"parallel_with": ["BLI-051", "BLI-052"],
|
||||
"scheduling": {
|
||||
"earliest_start": "After BLI-048 & BLI-049 complete",
|
||||
"can_parallelize": true,
|
||||
"parallelization_candidates": ["BLI-051", "BLI-052"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Parallelization Rules
|
||||
```javascript
|
||||
function canParallelize(itemA, itemB) {
|
||||
// No shared dependencies
|
||||
const sharedDeps = itemA.depends_on.filter(d =>
|
||||
itemB.depends_on.includes(d)
|
||||
);
|
||||
if (sharedDeps.length > 0) return false;
|
||||
|
||||
// Different agents
|
||||
if (itemA.assigned_agent === itemB.assigned_agent) return false;
|
||||
|
||||
// No blocking relationship
|
||||
if (itemA.blocks.includes(itemB.id)) return false;
|
||||
if (itemB.blocks.includes(itemA.id)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
### Optimal Schedule Generation
|
||||
```json
|
||||
{
|
||||
"schedule": {
|
||||
"week_1": {
|
||||
"parallel_tracks": [
|
||||
{ "agent": "frontend", "items": ["BLI-050", "BLI-051"] },
|
||||
{ "agent": "backend", "items": ["BLI-048", "BLI-049"] }
|
||||
],
|
||||
"capacity_used": "85%"
|
||||
},
|
||||
"week_2": {
|
||||
"parallel_tracks": [
|
||||
{ "agent": "frontend", "items": ["BLI-053"] },
|
||||
{ "agent": "backend", "items": ["BLI-052"] },
|
||||
{ "agent": "tester", "items": ["BLI-050-test", "BLI-051-test"] }
|
||||
],
|
||||
"capacity_used": "90%"
|
||||
}
|
||||
},
|
||||
"critical_path": ["BLI-048", "BLI-050", "BLI-053"],
|
||||
"total_duration": "2 weeks",
|
||||
"parallelization_savings": "40%"
|
||||
}
|
||||
```
|
||||
|
||||
## Output Format
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"framework": "wsjf",
|
||||
"prioritized_items": [
|
||||
{
|
||||
"rank": 1,
|
||||
"id": "BLI-043",
|
||||
"title": "User authentication",
|
||||
"score": 7.33,
|
||||
"category": "must_have",
|
||||
"quadrant": "quick_win"
|
||||
},
|
||||
{
|
||||
"rank": 2,
|
||||
"id": "BLI-050",
|
||||
"title": "Password reset",
|
||||
"score": 5.67,
|
||||
"category": "must_have",
|
||||
"quadrant": "major_project"
|
||||
}
|
||||
],
|
||||
"schedule": {
|
||||
"sprint_1": ["BLI-043", "BLI-045"],
|
||||
"sprint_2": ["BLI-050", "BLI-047"],
|
||||
"backlog": ["BLI-055", "BLI-060"]
|
||||
},
|
||||
"parallelization": {
|
||||
"recommended_groups": [
|
||||
["BLI-043", "BLI-044"],
|
||||
["BLI-050", "BLI-051"]
|
||||
],
|
||||
"time_savings": "35%"
|
||||
},
|
||||
"recommendations": [
|
||||
"BLI-050 has effort 9 - consider splitting",
|
||||
"BLI-043 and BLI-044 can run in parallel",
|
||||
"Remove BLI-060 - low impact, high effort"
|
||||
],
|
||||
"next_step": "Commit to sprint with /sprint plan"
|
||||
}
|
||||
```
|
||||
|
||||
## Decision Matrix Template
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ PRIORITIZATION DECISION │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Items Evaluated: 25 │
|
||||
│ Framework: WSJF + Effort/Impact │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ MUST DO (Score > 6) │ SHOULD DO (Score 4-6) │ │
|
||||
│ │ • User auth (7.33) │ • Dark mode (5.20) │ │
|
||||
│ │ • Password reset (6.67) │ • Notifications (4.80) │ │
|
||||
│ │ • Profile page (6.40) │ • Search (4.50) │ │
|
||||
│ ├───────────────────────────────────────────────────────┤ │
|
||||
│ │ COULD DO (Score 2-4) │ WON'T DO (Score < 2) │ │
|
||||
│ │ • Export CSV (3.50) │ • Social login (1.80) │ │
|
||||
│ │ • Keyboard shortcuts (2.90)│ • Mobile app (1.20) │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Recommended: Focus on MUST DO items for next 2 sprints │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Quality Gates
|
||||
- [ ] All items have consistent scoring
|
||||
- [ ] Dependencies documented
|
||||
- [ ] Parallelization opportunities identified
|
||||
- [ ] Schedule accounts for capacity
|
||||
- [ ] Clear decision rationale
|
||||
- [ ] Stakeholder alignment
|
||||
|
||||
## Token Budget
|
||||
- Max input: 1000 tokens
|
||||
- Max output: 1500 tokens
|
||||
|
||||
## Model
|
||||
- Recommended: sonnet (decision reasoning)
|
||||
|
||||
## Philosophy
|
||||
> "If everything is important, nothing is."
|
||||
|
||||
**Keep it simple:**
|
||||
- Prioritize ruthlessly
|
||||
- Say no to low-impact work
|
||||
- Parallelize aggressively
|
||||
- Ship the most valuable thing first
|
||||
331
skills/wws/overview.md
Normal file
331
skills/wws/overview.md
Normal file
@@ -0,0 +1,331 @@
|
||||
# Skill: WWS (Serverless Functions) Overview
|
||||
|
||||
## Description
|
||||
Architecture and implementation guide for WWS (Web Worker Services) - serverless functions for edge computing in the Mylder platform.
|
||||
|
||||
## What is WWS?
|
||||
WWS is our serverless function layer that runs lightweight compute at the edge, reducing VPS load and improving response times. Similar to Cloudflare Workers but platform-agnostic.
|
||||
|
||||
## Architecture
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ USER REQUEST │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ EDGE LAYER (WWS) │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Auth │ │ Rate │ │ Model │ │ Cache │ │
|
||||
│ │ Guard │ │ Limiter │ │ Router │ │ Manager │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌──────────────────┼──────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│synthetic │ │ z.ai │ │ Origin │
|
||||
│ .new │ │(fallback)│ │ VPS │
|
||||
└──────────┘ └──────────┘ └──────────┘
|
||||
```
|
||||
|
||||
## Core Functions
|
||||
|
||||
### 1. Auth Guard
|
||||
```javascript
|
||||
// Edge authentication validation
|
||||
export async function authGuard(request, env) {
|
||||
const token = request.headers.get('Authorization')?.split('Bearer ')[1];
|
||||
|
||||
// Fast KV lookup
|
||||
const session = await env.SESSIONS.get(token);
|
||||
if (session) {
|
||||
return { valid: true, user: JSON.parse(session), source: 'cache' };
|
||||
}
|
||||
|
||||
// Fallback to Supabase
|
||||
const supabaseUser = await validateWithSupabase(token, env);
|
||||
if (supabaseUser) {
|
||||
await env.SESSIONS.put(token, JSON.stringify(supabaseUser), {
|
||||
expirationTtl: 3600 // 1 hour
|
||||
});
|
||||
return { valid: true, user: supabaseUser, source: 'origin' };
|
||||
}
|
||||
|
||||
return { valid: false };
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Rate Limiter
|
||||
```javascript
|
||||
// Per-user, per-endpoint rate limiting
|
||||
export async function rateLimiter(request, env) {
|
||||
const userId = request.headers.get('X-User-ID') || 'anonymous';
|
||||
const endpoint = new URL(request.url).pathname;
|
||||
const key = `rate:${userId}:${endpoint}`;
|
||||
|
||||
const current = await env.RATE_LIMITS.get(key) || '0';
|
||||
const count = parseInt(current, 10);
|
||||
|
||||
const limits = {
|
||||
'/api/ai/chat': 60, // 60 requests per minute
|
||||
'/api/ai/generate': 20, // 20 per minute
|
||||
'default': 100 // 100 per minute
|
||||
};
|
||||
|
||||
const limit = limits[endpoint] || limits.default;
|
||||
|
||||
if (count >= limit) {
|
||||
return {
|
||||
allowed: false,
|
||||
retryAfter: 60,
|
||||
remaining: 0
|
||||
};
|
||||
}
|
||||
|
||||
await env.RATE_LIMITS.put(key, String(count + 1), {
|
||||
expirationTtl: 60
|
||||
});
|
||||
|
||||
return {
|
||||
allowed: true,
|
||||
remaining: limit - count - 1
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Model Router
|
||||
```javascript
|
||||
// Intelligent AI model routing
|
||||
export async function modelRouter(task, env) {
|
||||
const { type, complexity, context_length } = task;
|
||||
|
||||
// Route based on task characteristics
|
||||
const routing = {
|
||||
// Primary: synthetic.new
|
||||
primary: {
|
||||
provider: 'synthetic.new',
|
||||
base_url: 'https://api.synthetic.new/openai/v1',
|
||||
models: {
|
||||
code: 'hf:deepseek-ai/DeepSeek-V3',
|
||||
reasoning: 'hf:moonshotai/Kimi-K2-Thinking'
|
||||
}
|
||||
},
|
||||
// Fallback: z.ai
|
||||
fallback: {
|
||||
provider: 'z.ai',
|
||||
base_url: 'https://api.z.ai/v1',
|
||||
models: {
|
||||
code: 'glm-4-flash',
|
||||
reasoning: 'glm-4-plus',
|
||||
long_context: 'glm-4-long'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Special cases for z.ai
|
||||
if (context_length > 128000) {
|
||||
return {
|
||||
...routing.fallback,
|
||||
model: routing.fallback.models.long_context,
|
||||
reason: 'Context exceeds 128K, using GLM-4-Long'
|
||||
};
|
||||
}
|
||||
|
||||
// Default: synthetic.new
|
||||
const modelType = ['code', 'implementation', 'debugging'].includes(type)
|
||||
? 'code'
|
||||
: 'reasoning';
|
||||
|
||||
return {
|
||||
...routing.primary,
|
||||
model: routing.primary.models[modelType],
|
||||
reason: `Standard ${modelType} task`
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Cache Manager
|
||||
```javascript
|
||||
// Stale-while-revalidate caching
|
||||
export async function cacheManager(request, env, handler) {
|
||||
const cacheKey = new URL(request.url).pathname;
|
||||
|
||||
// Check cache
|
||||
const cached = await env.RESPONSE_CACHE.get(cacheKey, { type: 'json' });
|
||||
|
||||
if (cached) {
|
||||
const age = Date.now() - cached.timestamp;
|
||||
const maxAge = 60000; // 1 minute
|
||||
const staleAge = 300000; // 5 minutes
|
||||
|
||||
// Fresh cache
|
||||
if (age < maxAge) {
|
||||
return { data: cached.data, source: 'cache', age };
|
||||
}
|
||||
|
||||
// Stale-while-revalidate
|
||||
if (age < staleAge) {
|
||||
// Return stale, revalidate in background
|
||||
env.ctx.waitUntil(revalidate(cacheKey, handler, env));
|
||||
return { data: cached.data, source: 'stale', age };
|
||||
}
|
||||
}
|
||||
|
||||
// No cache, fetch fresh
|
||||
const fresh = await handler();
|
||||
await env.RESPONSE_CACHE.put(cacheKey, JSON.stringify({
|
||||
data: fresh,
|
||||
timestamp: Date.now()
|
||||
}));
|
||||
|
||||
return { data: fresh, source: 'origin', age: 0 };
|
||||
}
|
||||
|
||||
async function revalidate(key, handler, env) {
|
||||
const fresh = await handler();
|
||||
await env.RESPONSE_CACHE.put(key, JSON.stringify({
|
||||
data: fresh,
|
||||
timestamp: Date.now()
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
## Deployment Options
|
||||
|
||||
### Option 1: Cloudflare Workers
|
||||
```yaml
|
||||
# wrangler.toml
|
||||
name = "mylder-wws"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2024-12-01"
|
||||
|
||||
[[kv_namespaces]]
|
||||
binding = "SESSIONS"
|
||||
id = "xxx"
|
||||
|
||||
[[kv_namespaces]]
|
||||
binding = "RATE_LIMITS"
|
||||
id = "xxx"
|
||||
|
||||
[[kv_namespaces]]
|
||||
binding = "RESPONSE_CACHE"
|
||||
id = "xxx"
|
||||
```
|
||||
|
||||
### Option 2: Deno Deploy
|
||||
```typescript
|
||||
// main.ts
|
||||
import { serve } from "https://deno.land/std/http/server.ts";
|
||||
|
||||
serve(async (req) => {
|
||||
const url = new URL(req.url);
|
||||
|
||||
if (url.pathname.startsWith('/api/ai/')) {
|
||||
return handleAIRequest(req);
|
||||
}
|
||||
|
||||
return new Response('Not Found', { status: 404 });
|
||||
}, { port: 8000 });
|
||||
```
|
||||
|
||||
### Option 3: Self-Hosted (Docker)
|
||||
```dockerfile
|
||||
# Dockerfile.wws
|
||||
FROM denoland/deno:1.38.0
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
RUN deno cache main.ts
|
||||
|
||||
EXPOSE 8000
|
||||
CMD ["deno", "run", "--allow-net", "--allow-env", "main.ts"]
|
||||
```
|
||||
|
||||
## Integration Points
|
||||
|
||||
### n8n Workflow Integration
|
||||
```json
|
||||
{
|
||||
"name": "WWS Call",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://wws.mylder.io/api/ai/chat",
|
||||
"headers": {
|
||||
"Authorization": "Bearer {{ $env.WWS_API_KEY }}",
|
||||
"X-Task-Type": "{{ $json.taskType }}"
|
||||
},
|
||||
"body": {
|
||||
"messages": "{{ $json.messages }}",
|
||||
"context": "{{ $json.context }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Frontend Integration
|
||||
```typescript
|
||||
// lib/wws.ts
|
||||
export async function callWWS(endpoint: string, data: any) {
|
||||
const response = await fetch(`${process.env.NEXT_PUBLIC_WWS_URL}${endpoint}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${getSession().token}`
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
// Handle rate limiting
|
||||
if (response.status === 429) {
|
||||
const retryAfter = response.headers.get('Retry-After');
|
||||
throw new RateLimitError(retryAfter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
## Latency Targets
|
||||
| Operation | Target | Fallback |
|
||||
|-----------|--------|----------|
|
||||
| Auth validation | < 10ms | < 300ms (origin) |
|
||||
| Rate limit check | < 5ms | N/A |
|
||||
| Model routing | < 2ms | N/A |
|
||||
| Cache hit | < 10ms | N/A |
|
||||
| AI request (primary) | < 5s | < 10s (fallback) |
|
||||
|
||||
## Cost Model
|
||||
```
|
||||
Cloudflare Workers:
|
||||
- Free: 100K requests/day
|
||||
- Paid: $5/month + $0.50/million requests
|
||||
|
||||
KV Storage:
|
||||
- Free: 100K reads/day, 1K writes/day
|
||||
- Paid: $0.50/million reads, $5/million writes
|
||||
|
||||
Estimated (1M users/month):
|
||||
- Workers: ~$5/month
|
||||
- KV: ~$25/month
|
||||
- Total: ~$30/month
|
||||
```
|
||||
|
||||
## Related Skills
|
||||
- `wws/edge-auth.md` - Detailed auth implementation
|
||||
- `wws/rate-limit.md` - Rate limiting patterns
|
||||
- `wws/model-router.md` - AI model selection
|
||||
- `ai-providers/synthetic-new.md` - Primary AI provider
|
||||
- `ai-providers/z-ai.md` - Fallback provider
|
||||
|
||||
## Token Budget
|
||||
- Max input: 500 tokens
|
||||
- Max output: 1200 tokens
|
||||
|
||||
## Model
|
||||
- Recommended: sonnet (architecture understanding)
|
||||
Reference in New Issue
Block a user