@sweny-ai/core 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,6 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import { workflowZ, nodeZ, edgeZ, skillZ, toolZ, parseWorkflow, validateWorkflow, workflowJsonSchema, } from "../schema.js";
3
- import { triageWorkflow } from "../workflows/triage.js";
4
- import { implementWorkflow } from "../workflows/implement.js";
3
+ import { triageWorkflow, implementWorkflow } from "../workflows/index.js";
5
4
  // ─── Test fixtures ───────────────────────────────────────────────
6
5
  const validWorkflow = {
7
6
  id: "test-wf",
package/dist/cli/main.js CHANGED
@@ -7,9 +7,7 @@ const _require = createRequire(import.meta.url);
7
7
  const { version } = _require("../../package.json");
8
8
  import chalk from "chalk";
9
9
  import { execute } from "../executor.js";
10
- import { triageWorkflow } from "../workflows/triage.js";
11
- import { implementWorkflow } from "../workflows/implement.js";
12
- import { seedContentWorkflow } from "../workflows/seed-content.js";
10
+ import { triageWorkflow, implementWorkflow, seedContentWorkflow } from "../workflows/index.js";
13
11
  import { consoleLogger } from "../types.js";
14
12
  import { ClaudeClient } from "../claude.js";
15
13
  import { createSkillMap, configuredSkills } from "../skills/index.js";
@@ -7,8 +7,7 @@ import { execute } from "./executor.js";
7
7
  import { MockClaude, createFileSkill } from "./testing.js";
8
8
  import { createSkillMap } from "./skills/index.js";
9
9
  import { validateWorkflow, parseWorkflow } from "./schema.js";
10
- import { triageWorkflow } from "./workflows/triage.js";
11
- import { implementWorkflow } from "./workflows/implement.js";
10
+ import { triageWorkflow, implementWorkflow } from "./workflows/index.js";
12
11
  // ─── Test fixtures ───────────────────────────────────────────────
13
12
  const tmpBase = path.join(tmpdir(), "sweny-core-test");
14
13
  function freshDir(name) {
@@ -0,0 +1,3 @@
1
+ export const triageWorkflow = {"id":"triage","name":"Alert Triage","description":"Investigate a production alert, determine root cause, create an issue, implement a fix, and notify the team","entry":"prepare","nodes":{"prepare":{"name":"Load Rules & Context","instruction":"You are preparing for a triage workflow. Your job is to fetch and review any knowledge documents listed in the input.\n\n1. Check input for `rules_urls` and `context_urls` arrays.\n2. For each URL, fetch its content:\n - Linear document URLs → use the Linear MCP tools (get_document or search_documentation)\n - Other HTTP URLs → fetch directly\n3. Summarize the key rules and context that downstream workflow nodes should follow.\n4. Output the consolidated information so it's available to all subsequent steps.\n\nIf there are no URLs to fetch, just pass through — this step is a no-op.","skills":["linear"]},"gather":{"name":"Gather Context","instruction":"You are investigating a production alert. Gather all relevant context using the available tools:\n\n1. **Observability**: Pull error details, stack traces, recent logs, metrics, and active incidents around the time of the alert. Use whichever observability tools are available to you.\n2. **Source control**: Check recent commits, pull requests, and deploys that might be related.\n3. **Issue tracker**: Search for similar past issues or known problems.\n\nBe thorough — the investigation step depends on complete context. Use every tool available to you.","skills":["github","sentry","datadog","betterstack","linear"]},"investigate":{"name":"Root Cause Analysis","instruction":"Based on the gathered context, classify every distinct issue you found into one of two buckets: **novel** or **duplicate**.\n\nFor EACH issue found:\n1. Identify the root cause and affected code/service.\n2. Assess severity: critical (service down), high (major feature broken), medium (degraded), low (cosmetic/minor).\n3. Assess fix complexity: \"simple\" (a few lines, clear change), \"moderate\" (multiple files but well-understood), or \"complex\" (architectural, risky, or unclear).\n4. **Novelty check (REQUIRED):** Search the issue tracker for existing issues (BOTH open AND closed) that cover the same root cause, error pattern, or affected service. Use github_search_issues and/or linear_search_issues with multiple keyword variations.\n - A match = same root cause, same error message/pattern, or a human would call it \"the same bug.\"\n - If matched → it's a **duplicate**. Record the existing issue ID.\n - If no match → it's **novel**.\n\n**Output rules:**\n- `findings`: array of ALL issues found (both novel and duplicate).\n- `novel_count`: how many findings are novel (not duplicates).\n- `highest_severity`: the highest severity across ALL findings.\n- `recommendation`: what should happen next.\n\nDownstream nodes will act ONLY on novel findings. Duplicates will be +1'd automatically.","skills":["github","linear"],"output":{"type":"object","properties":{"findings":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"Short description of the issue"},"root_cause":{"type":"string"},"severity":{"type":"string","enum":["critical","high","medium","low"]},"affected_services":{"type":"array","items":{"type":"string"}},"is_duplicate":{"type":"boolean"},"duplicate_of":{"type":"string","description":"Existing issue ID/URL if duplicate"},"fix_approach":{"type":"string"},"fix_complexity":{"type":"string","enum":["simple","moderate","complex"]}},"required":["title","root_cause","severity","is_duplicate"]}},"novel_count":{"type":"number","description":"Count of novel (non-duplicate) findings"},"highest_severity":{"type":"string","enum":["critical","high","medium","low"]},"recommendation":{"type":"string"}},"required":["findings","novel_count","highest_severity","recommendation"]}},"create_issue":{"name":"Create Issues & Triage Duplicates","instruction":"Process ALL findings from the investigation. The findings array contains both novel and duplicate issues.\n\n**For each NOVEL finding** (is_duplicate = false):\n1. Create a new issue with a clear, actionable title.\n2. Include: root cause, severity, affected services, reproduction steps, and recommended fix.\n3. Add appropriate labels (bug, severity level, affected service).\n4. Link to relevant commits, PRs, or existing issues.\n\n**For each DUPLICATE finding** (is_duplicate = true):\n1. Find the existing issue (check duplicate_of field).\n2. Check the issue's comments — if the most recent comment is already from SWEny (contains \"+1\") within the last 24 hours, skip adding another comment.\n3. Otherwise add a SHORT comment: \"+1 — seen again {UTC timestamp}. {one sentence of new context}.\" (Keep it under 2 lines. No markdown headers, no emoji, no formatting.)\n4. If the existing issue is closed/done, reopen it.\n\nIf context.issueTemplate is provided, use it as the format for new issue bodies. Otherwise use a clear structure with: Summary, Root Cause, Impact, Steps to Reproduce, and Recommended Fix.\n\nUse whichever issue tracker is available to you. Output the created/updated issue identifiers.","skills":["linear","github"]},"skip":{"name":"Skip — All Duplicates or Low Priority","instruction":"Every finding from the investigation was either a duplicate or low-priority. No new issues need to be created.\n\nFor each **duplicate** finding (check the findings array for items where is_duplicate = true):\n1. Find the existing issue (check duplicate_of field).\n2. Check the issue's comments — if the most recent comment is already from SWEny (contains \"+1\") within the last 24 hours, skip adding another comment.\n3. Otherwise add a SHORT comment: \"+1 — seen again {UTC timestamp}. {one sentence of new context}.\" (Keep it under 2 lines. No markdown headers, no emoji, no formatting.)\n4. If the issue is closed/done, reopen it.\n\nFor **low priority** findings, log a brief note about why they were skipped.","skills":["linear","github"]},"implement":{"name":"Implement Fix","instruction":"Implement the fix identified during investigation:\n\n1. Create a feature branch from the base branch (check context for baseBranch, default \"main\").\n2. Read the relevant source files to understand the current code.\n3. Make the necessary code changes — fix the bug, nothing more.\n4. Run any existing tests if available to verify the fix doesn't break anything.\n5. Stage and commit with a clear commit message referencing the issue.\n\nKeep changes minimal and focused. Do not refactor surrounding code or add unrelated improvements.\n\nIf the fix turns out to be more complex than expected, stop and explain why — do not force a bad fix.","skills":["github"]},"create_pr":{"name":"Open Pull Request","instruction":"Open a pull request for the fix:\n\n1. Push the branch to the remote.\n2. Create a PR with a clear title referencing the issue (e.g. \"[OFF-1020] fix: guard empty pdf_texts before access\").\n3. In the PR body, include: summary of the bug, what the fix does, and a link to the issue.\n4. Add appropriate labels if available.\n\nIf context.prTemplate is provided, use it as the format for the PR body. Otherwise use a clear structure with: Summary, Changes, Testing, and Related Issues.\n\nReturn the PR URL and number.","skills":["github"]},"notify":{"name":"Notify Team","instruction":"Send a notification summarizing the triage result:\n\n1. Include: alert summary, severity, root cause (1-2 sentences), and links to any created issues or PRs.\n2. For critical/high severity, make the notification urgent.\n3. For medium/low, a standard notification is fine.\n\nUse whichever notification channel is available to you.","skills":["slack","notification"]}},"edges":[{"from":"prepare","to":"gather"},{"from":"gather","to":"investigate"},{"from":"investigate","to":"create_issue","when":"novel_count is greater than 0 AND highest_severity is medium or higher"},{"from":"investigate","to":"skip","when":"novel_count is 0, OR highest_severity is low"},{"from":"create_issue","to":"implement","when":"at least one novel finding has fix_complexity simple or moderate AND fix_approach is provided"},{"from":"create_issue","to":"notify","when":"all novel findings have fix_complexity complex, OR no clear fix_approach"},{"from":"skip","to":"notify"},{"from":"implement","to":"create_pr"},{"from":"create_pr","to":"notify"}]};
2
+ export const implementWorkflow = {"id":"implement","name":"Implement Fix","description":"Implement a code fix for an issue and open a pull request","entry":"analyze","nodes":{"analyze":{"name":"Analyze Issue","instruction":"Read the issue details and understand what needs to be fixed:\n\n1. Fetch the issue from the tracker (GitHub or Linear).\n2. Read the relevant source files to understand the current code.\n3. Identify the exact files and lines that need to change.\n4. Plan the fix approach.\n\nOutput a clear analysis of what needs to change and why.","skills":["github","linear"],"output":{"type":"object","properties":{"issue_summary":{"type":"string"},"files_to_change":{"type":"array","items":{"type":"string"}},"fix_plan":{"type":"string"},"risk_level":{"type":"string","enum":["low","medium","high"]}},"required":["issue_summary","fix_plan"]}},"implement":{"name":"Implement Fix","instruction":"Implement the planned fix:\n\n1. Create a feature branch.\n2. Make the necessary code changes.\n3. Ensure changes are minimal and focused — fix the bug, nothing more.\n4. Stage and commit with a clear commit message referencing the issue.\n\nIf the fix is too risky or complex, explain why and skip.","skills":["github"]},"create_pr":{"name":"Open Pull Request","instruction":"Open a pull request for the fix:\n\n1. Push the branch to the remote.\n2. Create a PR with a clear title and description.\n3. Reference the original issue in the PR body.\n4. Add appropriate reviewers or labels if possible.\n\nIf context.prTemplate is provided, use it as the format for the PR body. Otherwise use a clear structure with: Summary, Changes, Testing, and Related Issues.\n\nReturn the PR URL.","skills":["github"]},"notify":{"name":"Notify","instruction":"Send a notification about the implementation result:\n\n1. Include: issue reference, PR link, brief summary of changes.\n2. Keep it concise — one message, not a wall of text.","skills":["slack","notification"]},"skip":{"name":"Skip — Too Complex","instruction":"The fix was determined to be too complex or risky for automated implementation.\nAdd a comment to the issue explaining what was found and why it needs manual attention.","skills":["github","linear"]}},"edges":[{"from":"analyze","to":"implement","when":"Fix risk level is low or medium and a clear plan exists"},{"from":"analyze","to":"skip","when":"Fix is too complex, risky, or unclear"},{"from":"implement","to":"create_pr"},{"from":"create_pr","to":"notify"}]};
3
+ export const seedContentWorkflow = {"id":"seed-content","name":"Content Generation Pipeline","description":"Audit content gaps, generate educational content, validate quality, and publish to Supabase","entry":"audit","nodes":{"audit":{"name":"Audit Content Gaps","instruction":"You are auditing an educational platform's content library.\n\nUse supabase_count to check how many items exist for each combination of:\n- Content types: worksheets, games, lessons\n- Subjects: math, science, english, history, geography, economics, music, art, life-skills, foreign-language\n- Difficulties: beginner, easy, medium, hard\n\nAlso check the input parameters — if the user specified a subject, topic, difficulty, and count,\nskip the full audit and just report what they want generated.\n\nReturn a structured content plan: what to generate, how many, at what difficulty and grade level.\nPrioritize gaps where a subject has ZERO content of a given type.","skills":["supabase"],"output":{"type":"object","properties":{"plan":{"type":"array","items":{"type":"object","properties":{"contentType":{"type":"string"},"subject":{"type":"string"},"topic":{"type":"string"},"difficulty":{"type":"string"},"gradeLevel":{"type":"string"},"count":{"type":"number"},"reason":{"type":"string"}},"required":["contentType","subject","topic","difficulty","count"]}},"summary":{"type":"string"}},"required":["plan","summary"]}},"generate":{"name":"Generate Content","instruction":"You are an expert educator creating content for children ages 5-14.\n\nFor each item in the content plan from the previous step, generate the content directly.\nThe content must be high-quality, engaging, age-appropriate, and educationally sound.\n\n**For worksheets:**\nGenerate a JSON array of problems. Each problem needs: \"problem\", \"answer\", \"format\" (answer-line | multiple-choice | write-on).\nRequirements:\n- Every answer MUST be correct. Double-check math, facts, spelling.\n- Problems must progress in difficulty within the set.\n- Use at least 2 different problem structures (e.g., equations + word problems for math).\n- Vary phrasing — no two problems should feel copy-pasted.\n- For the target grade level, use appropriate vocabulary and complexity.\n\n**For lessons:**\nGenerate complete HTML + CSS + JS for an interactive lesson.\nRequirements:\n- Must have substantial educational content (not just a shell with navigation).\n- Include interactive elements: quizzes, click-to-reveal, drag-and-drop.\n- Must be visually engaging with colors, icons, and clear typography.\n- Include practice exercises with immediate feedback.\n- Minimum 5 teaching sections plus 2 practice activities.\n\n**For games:**\nGenerate a description and educational requirements only (actual game code is generated\nby the platform's Phaser-based generator).\n\nUse supabase_insert to write each piece of content to the appropriate table.\n\nTable schemas:\n- worksheets: id (auto), title, subject, topic, difficulty, grade_level, num_questions, problems (jsonb), status='published', source='ai-seed'\n- lessons: id (auto), title, subject, difficulty, grade_level, lesson_type, html_code, css_code, js_code, status='published', source='ai-seed'\n- games: id (auto), title, subject, difficulty, grade_level, game_type, html_code, css_code, js_code, status='published', source='ai-seed'\n\nReturn a summary of what was generated and inserted.","skills":["supabase"],"output":{"type":"object","properties":{"generated":{"type":"array","items":{"type":"object","properties":{"contentType":{"type":"string"},"title":{"type":"string"},"subject":{"type":"string"},"id":{"type":"string"},"status":{"type":"string"}}}},"totalGenerated":{"type":"number"},"errors":{"type":"array","items":{"type":"string"}}},"required":["generated","totalGenerated"]}},"validate":{"name":"Validate Content Quality","instruction":"Review the content that was just generated and inserted.\n\nFor each item, use supabase_query to fetch it back and verify:\n\n**Worksheets:**\n- Parse the problems JSON — are all answers correct?\n- Are problems diverse (not repetitive)?\n- Is difficulty appropriate for the stated grade level?\n- Are there the right number of questions?\n\n**Lessons:**\n- Is the HTML substantial (> 500 characters)?\n- Does it contain actual educational content (not just navigation shells)?\n- Are there interactive elements?\n\n**Games:**\n- Does the HTML contain a working game structure?\n\nFlag any issues. If critical issues are found (wrong answers, empty content),\nuse supabase_update to set status='draft' and add a note.\n\nReturn a quality report.","skills":["supabase"],"output":{"type":"object","properties":{"totalReviewed":{"type":"number"},"passed":{"type":"number"},"flagged":{"type":"number"},"issues":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"issue":{"type":"string"},"severity":{"type":"string"},"action":{"type":"string"}}}},"summary":{"type":"string"}},"required":["totalReviewed","passed","flagged","summary"]}},"report":{"name":"Generate Report","instruction":"Compile a final report of the content generation run.\n\nInclude:\n- Total content generated by type and subject\n- Quality validation results\n- Any issues found and actions taken\n- Recommendations for next content generation run (what gaps remain)\n\nFormat as a clean markdown summary that a solo operator can scan in 30 seconds.","skills":[],"output":{"type":"object","properties":{"markdown":{"type":"string"},"nextPriorities":{"type":"array","items":{"type":"string"}}},"required":["markdown"]}}},"edges":[{"from":"audit","to":"generate"},{"from":"generate","to":"validate"},{"from":"validate","to":"report"}]};
@@ -0,0 +1,103 @@
1
+ id: implement
2
+ name: Implement Fix
3
+ description: Implement a code fix for an issue and open a pull request
4
+ entry: analyze
5
+ nodes:
6
+ analyze:
7
+ name: Analyze Issue
8
+ instruction: |-
9
+ Read the issue details and understand what needs to be fixed:
10
+
11
+ 1. Fetch the issue from the tracker (GitHub or Linear).
12
+ 2. Read the relevant source files to understand the current code.
13
+ 3. Identify the exact files and lines that need to change.
14
+ 4. Plan the fix approach.
15
+
16
+ Output a clear analysis of what needs to change and why.
17
+ skills:
18
+ - github
19
+ - linear
20
+ output:
21
+ type: object
22
+ properties:
23
+ issue_summary:
24
+ type: string
25
+ files_to_change:
26
+ type: array
27
+ items:
28
+ type: string
29
+ fix_plan:
30
+ type: string
31
+ risk_level:
32
+ type: string
33
+ enum:
34
+ - low
35
+ - medium
36
+ - high
37
+ required:
38
+ - issue_summary
39
+ - fix_plan
40
+ implement:
41
+ name: Implement Fix
42
+ instruction: |-
43
+ Implement the planned fix:
44
+
45
+ 1. Create a feature branch.
46
+ 2. Make the necessary code changes.
47
+ 3. Ensure changes are minimal and focused — fix the bug, nothing more.
48
+ 4. Stage and commit with a clear commit message referencing the issue.
49
+
50
+ If the fix is too risky or complex, explain why and skip.
51
+ skills:
52
+ - github
53
+ create_pr:
54
+ name: Open Pull Request
55
+ instruction: >-
56
+ Open a pull request for the fix:
57
+
58
+
59
+ 1. Push the branch to the remote.
60
+
61
+ 2. Create a PR with a clear title and description.
62
+
63
+ 3. Reference the original issue in the PR body.
64
+
65
+ 4. Add appropriate reviewers or labels if possible.
66
+
67
+
68
+ If context.prTemplate is provided, use it as the format for the PR body. Otherwise use a clear structure with:
69
+ Summary, Changes, Testing, and Related Issues.
70
+
71
+
72
+ Return the PR URL.
73
+ skills:
74
+ - github
75
+ notify:
76
+ name: Notify
77
+ instruction: |-
78
+ Send a notification about the implementation result:
79
+
80
+ 1. Include: issue reference, PR link, brief summary of changes.
81
+ 2. Keep it concise — one message, not a wall of text.
82
+ skills:
83
+ - slack
84
+ - notification
85
+ skip:
86
+ name: Skip — Too Complex
87
+ instruction: |-
88
+ The fix was determined to be too complex or risky for automated implementation.
89
+ Add a comment to the issue explaining what was found and why it needs manual attention.
90
+ skills:
91
+ - github
92
+ - linear
93
+ edges:
94
+ - from: analyze
95
+ to: implement
96
+ when: Fix risk level is low or medium and a clear plan exists
97
+ - from: analyze
98
+ to: skip
99
+ when: Fix is too complex, risky, or unclear
100
+ - from: implement
101
+ to: create_pr
102
+ - from: create_pr
103
+ to: notify
@@ -1,3 +1,4 @@
1
- export { triageWorkflow } from "./triage.js";
2
- export { implementWorkflow } from "./implement.js";
3
- export { seedContentWorkflow } from "./seed-content.js";
1
+ import type { Workflow } from "../types.js";
2
+ export declare const triageWorkflow: Workflow;
3
+ export declare const implementWorkflow: Workflow;
4
+ export declare const seedContentWorkflow: Workflow;
@@ -1,3 +1,12 @@
1
- export { triageWorkflow } from "./triage.js";
2
- export { implementWorkflow } from "./implement.js";
3
- export { seedContentWorkflow } from "./seed-content.js";
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { parse as parseYaml } from "yaml";
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ function loadBuiltinWorkflow(filename) {
7
+ const filePath = path.join(__dirname, filename);
8
+ return parseYaml(fs.readFileSync(filePath, "utf-8"));
9
+ }
10
+ export const triageWorkflow = loadBuiltinWorkflow("triage.yml");
11
+ export const implementWorkflow = loadBuiltinWorkflow("implement.yml");
12
+ export const seedContentWorkflow = loadBuiltinWorkflow("seed-content.yml");
@@ -0,0 +1,242 @@
1
+ id: seed-content
2
+ name: Content Generation Pipeline
3
+ description: Audit content gaps, generate educational content, validate quality, and publish to Supabase
4
+ entry: audit
5
+ nodes:
6
+ audit:
7
+ name: Audit Content Gaps
8
+ instruction: |-
9
+ You are auditing an educational platform's content library.
10
+
11
+ Use supabase_count to check how many items exist for each combination of:
12
+ - Content types: worksheets, games, lessons
13
+ - Subjects: math, science, english, history, geography, economics, music, art, life-skills, foreign-language
14
+ - Difficulties: beginner, easy, medium, hard
15
+
16
+ Also check the input parameters — if the user specified a subject, topic, difficulty, and count,
17
+ skip the full audit and just report what they want generated.
18
+
19
+ Return a structured content plan: what to generate, how many, at what difficulty and grade level.
20
+ Prioritize gaps where a subject has ZERO content of a given type.
21
+ skills:
22
+ - supabase
23
+ output:
24
+ type: object
25
+ properties:
26
+ plan:
27
+ type: array
28
+ items:
29
+ type: object
30
+ properties:
31
+ contentType:
32
+ type: string
33
+ subject:
34
+ type: string
35
+ topic:
36
+ type: string
37
+ difficulty:
38
+ type: string
39
+ gradeLevel:
40
+ type: string
41
+ count:
42
+ type: number
43
+ reason:
44
+ type: string
45
+ required:
46
+ - contentType
47
+ - subject
48
+ - topic
49
+ - difficulty
50
+ - count
51
+ summary:
52
+ type: string
53
+ required:
54
+ - plan
55
+ - summary
56
+ generate:
57
+ name: Generate Content
58
+ instruction: >-
59
+ You are an expert educator creating content for children ages 5-14.
60
+
61
+
62
+ For each item in the content plan from the previous step, generate the content directly.
63
+
64
+ The content must be high-quality, engaging, age-appropriate, and educationally sound.
65
+
66
+
67
+ **For worksheets:**
68
+
69
+ Generate a JSON array of problems. Each problem needs: "problem", "answer", "format" (answer-line |
70
+ multiple-choice | write-on).
71
+
72
+ Requirements:
73
+
74
+ - Every answer MUST be correct. Double-check math, facts, spelling.
75
+
76
+ - Problems must progress in difficulty within the set.
77
+
78
+ - Use at least 2 different problem structures (e.g., equations + word problems for math).
79
+
80
+ - Vary phrasing — no two problems should feel copy-pasted.
81
+
82
+ - For the target grade level, use appropriate vocabulary and complexity.
83
+
84
+
85
+ **For lessons:**
86
+
87
+ Generate complete HTML + CSS + JS for an interactive lesson.
88
+
89
+ Requirements:
90
+
91
+ - Must have substantial educational content (not just a shell with navigation).
92
+
93
+ - Include interactive elements: quizzes, click-to-reveal, drag-and-drop.
94
+
95
+ - Must be visually engaging with colors, icons, and clear typography.
96
+
97
+ - Include practice exercises with immediate feedback.
98
+
99
+ - Minimum 5 teaching sections plus 2 practice activities.
100
+
101
+
102
+ **For games:**
103
+
104
+ Generate a description and educational requirements only (actual game code is generated
105
+
106
+ by the platform's Phaser-based generator).
107
+
108
+
109
+ Use supabase_insert to write each piece of content to the appropriate table.
110
+
111
+
112
+ Table schemas:
113
+
114
+ - worksheets: id (auto), title, subject, topic, difficulty, grade_level, num_questions, problems (jsonb),
115
+ status='published', source='ai-seed'
116
+
117
+ - lessons: id (auto), title, subject, difficulty, grade_level, lesson_type, html_code, css_code, js_code,
118
+ status='published', source='ai-seed'
119
+
120
+ - games: id (auto), title, subject, difficulty, grade_level, game_type, html_code, css_code, js_code,
121
+ status='published', source='ai-seed'
122
+
123
+
124
+ Return a summary of what was generated and inserted.
125
+ skills:
126
+ - supabase
127
+ output:
128
+ type: object
129
+ properties:
130
+ generated:
131
+ type: array
132
+ items:
133
+ type: object
134
+ properties:
135
+ contentType:
136
+ type: string
137
+ title:
138
+ type: string
139
+ subject:
140
+ type: string
141
+ id:
142
+ type: string
143
+ status:
144
+ type: string
145
+ totalGenerated:
146
+ type: number
147
+ errors:
148
+ type: array
149
+ items:
150
+ type: string
151
+ required:
152
+ - generated
153
+ - totalGenerated
154
+ validate:
155
+ name: Validate Content Quality
156
+ instruction: |-
157
+ Review the content that was just generated and inserted.
158
+
159
+ For each item, use supabase_query to fetch it back and verify:
160
+
161
+ **Worksheets:**
162
+ - Parse the problems JSON — are all answers correct?
163
+ - Are problems diverse (not repetitive)?
164
+ - Is difficulty appropriate for the stated grade level?
165
+ - Are there the right number of questions?
166
+
167
+ **Lessons:**
168
+ - Is the HTML substantial (> 500 characters)?
169
+ - Does it contain actual educational content (not just navigation shells)?
170
+ - Are there interactive elements?
171
+
172
+ **Games:**
173
+ - Does the HTML contain a working game structure?
174
+
175
+ Flag any issues. If critical issues are found (wrong answers, empty content),
176
+ use supabase_update to set status='draft' and add a note.
177
+
178
+ Return a quality report.
179
+ skills:
180
+ - supabase
181
+ output:
182
+ type: object
183
+ properties:
184
+ totalReviewed:
185
+ type: number
186
+ passed:
187
+ type: number
188
+ flagged:
189
+ type: number
190
+ issues:
191
+ type: array
192
+ items:
193
+ type: object
194
+ properties:
195
+ id:
196
+ type: string
197
+ title:
198
+ type: string
199
+ issue:
200
+ type: string
201
+ severity:
202
+ type: string
203
+ action:
204
+ type: string
205
+ summary:
206
+ type: string
207
+ required:
208
+ - totalReviewed
209
+ - passed
210
+ - flagged
211
+ - summary
212
+ report:
213
+ name: Generate Report
214
+ instruction: |-
215
+ Compile a final report of the content generation run.
216
+
217
+ Include:
218
+ - Total content generated by type and subject
219
+ - Quality validation results
220
+ - Any issues found and actions taken
221
+ - Recommendations for next content generation run (what gaps remain)
222
+
223
+ Format as a clean markdown summary that a solo operator can scan in 30 seconds.
224
+ skills: []
225
+ output:
226
+ type: object
227
+ properties:
228
+ markdown:
229
+ type: string
230
+ nextPriorities:
231
+ type: array
232
+ items:
233
+ type: string
234
+ required:
235
+ - markdown
236
+ edges:
237
+ - from: audit
238
+ to: generate
239
+ - from: generate
240
+ to: validate
241
+ - from: validate
242
+ to: report
@@ -0,0 +1,279 @@
1
+ id: triage
2
+ name: Alert Triage
3
+ description: Investigate a production alert, determine root cause, create an issue, implement a fix, and notify the team
4
+ entry: prepare
5
+ nodes:
6
+ prepare:
7
+ name: Load Rules & Context
8
+ instruction: >-
9
+ You are preparing for a triage workflow. Your job is to fetch and review any knowledge documents listed in the
10
+ input.
11
+
12
+
13
+ 1. Check input for `rules_urls` and `context_urls` arrays.
14
+
15
+ 2. For each URL, fetch its content:
16
+ - Linear document URLs → use the Linear MCP tools (get_document or search_documentation)
17
+ - Other HTTP URLs → fetch directly
18
+ 3. Summarize the key rules and context that downstream workflow nodes should follow.
19
+
20
+ 4. Output the consolidated information so it's available to all subsequent steps.
21
+
22
+
23
+ If there are no URLs to fetch, just pass through — this step is a no-op.
24
+ skills:
25
+ - linear
26
+ gather:
27
+ name: Gather Context
28
+ instruction: >-
29
+ You are investigating a production alert. Gather all relevant context using the available tools:
30
+
31
+
32
+ 1. **Observability**: Pull error details, stack traces, recent logs, metrics, and active incidents around the time
33
+ of the alert. Use whichever observability tools are available to you.
34
+
35
+ 2. **Source control**: Check recent commits, pull requests, and deploys that might be related.
36
+
37
+ 3. **Issue tracker**: Search for similar past issues or known problems.
38
+
39
+
40
+ Be thorough — the investigation step depends on complete context. Use every tool available to you.
41
+ skills:
42
+ - github
43
+ - sentry
44
+ - datadog
45
+ - betterstack
46
+ - linear
47
+ investigate:
48
+ name: Root Cause Analysis
49
+ instruction: >-
50
+ Based on the gathered context, classify every distinct issue you found into one of two buckets: **novel** or
51
+ **duplicate**.
52
+
53
+
54
+ For EACH issue found:
55
+
56
+ 1. Identify the root cause and affected code/service.
57
+
58
+ 2. Assess severity: critical (service down), high (major feature broken), medium (degraded), low (cosmetic/minor).
59
+
60
+ 3. Assess fix complexity: "simple" (a few lines, clear change), "moderate" (multiple files but well-understood),
61
+ or "complex" (architectural, risky, or unclear).
62
+
63
+ 4. **Novelty check (REQUIRED):** Search the issue tracker for existing issues (BOTH open AND closed) that cover
64
+ the same root cause, error pattern, or affected service. Use github_search_issues and/or linear_search_issues with
65
+ multiple keyword variations.
66
+ - A match = same root cause, same error message/pattern, or a human would call it "the same bug."
67
+ - If matched → it's a **duplicate**. Record the existing issue ID.
68
+ - If no match → it's **novel**.
69
+
70
+ **Output rules:**
71
+
72
+ - `findings`: array of ALL issues found (both novel and duplicate).
73
+
74
+ - `novel_count`: how many findings are novel (not duplicates).
75
+
76
+ - `highest_severity`: the highest severity across ALL findings.
77
+
78
+ - `recommendation`: what should happen next.
79
+
80
+
81
+ Downstream nodes will act ONLY on novel findings. Duplicates will be +1'd automatically.
82
+ skills:
83
+ - github
84
+ - linear
85
+ output:
86
+ type: object
87
+ properties:
88
+ findings:
89
+ type: array
90
+ items:
91
+ type: object
92
+ properties:
93
+ title:
94
+ type: string
95
+ description: Short description of the issue
96
+ root_cause:
97
+ type: string
98
+ severity:
99
+ type: string
100
+ enum:
101
+ - critical
102
+ - high
103
+ - medium
104
+ - low
105
+ affected_services:
106
+ type: array
107
+ items:
108
+ type: string
109
+ is_duplicate:
110
+ type: boolean
111
+ duplicate_of:
112
+ type: string
113
+ description: Existing issue ID/URL if duplicate
114
+ fix_approach:
115
+ type: string
116
+ fix_complexity:
117
+ type: string
118
+ enum:
119
+ - simple
120
+ - moderate
121
+ - complex
122
+ required:
123
+ - title
124
+ - root_cause
125
+ - severity
126
+ - is_duplicate
127
+ novel_count:
128
+ type: number
129
+ description: Count of novel (non-duplicate) findings
130
+ highest_severity:
131
+ type: string
132
+ enum:
133
+ - critical
134
+ - high
135
+ - medium
136
+ - low
137
+ recommendation:
138
+ type: string
139
+ required:
140
+ - findings
141
+ - novel_count
142
+ - highest_severity
143
+ - recommendation
144
+ create_issue:
145
+ name: Create Issues & Triage Duplicates
146
+ instruction: >-
147
+ Process ALL findings from the investigation. The findings array contains both novel and duplicate issues.
148
+
149
+
150
+ **For each NOVEL finding** (is_duplicate = false):
151
+
152
+ 1. Create a new issue with a clear, actionable title.
153
+
154
+ 2. Include: root cause, severity, affected services, reproduction steps, and recommended fix.
155
+
156
+ 3. Add appropriate labels (bug, severity level, affected service).
157
+
158
+ 4. Link to relevant commits, PRs, or existing issues.
159
+
160
+
161
+ **For each DUPLICATE finding** (is_duplicate = true):
162
+
163
+ 1. Find the existing issue (check duplicate_of field).
164
+
165
+ 2. Check the issue's comments — if the most recent comment is already from SWEny (contains "+1") within the last
166
+ 24 hours, skip adding another comment.
167
+
168
+ 3. Otherwise add a SHORT comment: "+1 — seen again {UTC timestamp}. {one sentence of new context}." (Keep it under
169
+ 2 lines. No markdown headers, no emoji, no formatting.)
170
+
171
+ 4. If the existing issue is closed/done, reopen it.
172
+
173
+
174
+ If context.issueTemplate is provided, use it as the format for new issue bodies. Otherwise use a clear structure
175
+ with: Summary, Root Cause, Impact, Steps to Reproduce, and Recommended Fix.
176
+
177
+
178
+ Use whichever issue tracker is available to you. Output the created/updated issue identifiers.
179
+ skills:
180
+ - linear
181
+ - github
182
+ skip:
183
+ name: Skip — All Duplicates or Low Priority
184
+ instruction: >-
185
+ Every finding from the investigation was either a duplicate or low-priority. No new issues need to be created.
186
+
187
+
188
+ For each **duplicate** finding (check the findings array for items where is_duplicate = true):
189
+
190
+ 1. Find the existing issue (check duplicate_of field).
191
+
192
+ 2. Check the issue's comments — if the most recent comment is already from SWEny (contains "+1") within the last
193
+ 24 hours, skip adding another comment.
194
+
195
+ 3. Otherwise add a SHORT comment: "+1 — seen again {UTC timestamp}. {one sentence of new context}." (Keep it under
196
+ 2 lines. No markdown headers, no emoji, no formatting.)
197
+
198
+ 4. If the issue is closed/done, reopen it.
199
+
200
+
201
+ For **low priority** findings, log a brief note about why they were skipped.
202
+ skills:
203
+ - linear
204
+ - github
205
+ implement:
206
+ name: Implement Fix
207
+ instruction: |-
208
+ Implement the fix identified during investigation:
209
+
210
+ 1. Create a feature branch from the base branch (check context for baseBranch, default "main").
211
+ 2. Read the relevant source files to understand the current code.
212
+ 3. Make the necessary code changes — fix the bug, nothing more.
213
+ 4. Run any existing tests if available to verify the fix doesn't break anything.
214
+ 5. Stage and commit with a clear commit message referencing the issue.
215
+
216
+ Keep changes minimal and focused. Do not refactor surrounding code or add unrelated improvements.
217
+
218
+ If the fix turns out to be more complex than expected, stop and explain why — do not force a bad fix.
219
+ skills:
220
+ - github
221
+ create_pr:
222
+ name: Open Pull Request
223
+ instruction: >-
224
+ Open a pull request for the fix:
225
+
226
+
227
+ 1. Push the branch to the remote.
228
+
229
+ 2. Create a PR with a clear title referencing the issue (e.g. "[OFF-1020] fix: guard empty pdf_texts before
230
+ access").
231
+
232
+ 3. In the PR body, include: summary of the bug, what the fix does, and a link to the issue.
233
+
234
+ 4. Add appropriate labels if available.
235
+
236
+
237
+ If context.prTemplate is provided, use it as the format for the PR body. Otherwise use a clear structure with:
238
+ Summary, Changes, Testing, and Related Issues.
239
+
240
+
241
+ Return the PR URL and number.
242
+ skills:
243
+ - github
244
+ notify:
245
+ name: Notify Team
246
+ instruction: |-
247
+ Send a notification summarizing the triage result:
248
+
249
+ 1. Include: alert summary, severity, root cause (1-2 sentences), and links to any created issues or PRs.
250
+ 2. For critical/high severity, make the notification urgent.
251
+ 3. For medium/low, a standard notification is fine.
252
+
253
+ Use whichever notification channel is available to you.
254
+ skills:
255
+ - slack
256
+ - notification
257
+ edges:
258
+ - from: prepare
259
+ to: gather
260
+ - from: gather
261
+ to: investigate
262
+ - from: investigate
263
+ to: create_issue
264
+ when: novel_count is greater than 0 AND highest_severity is medium or higher
265
+ - from: investigate
266
+ to: skip
267
+ when: novel_count is 0, OR highest_severity is low
268
+ - from: create_issue
269
+ to: implement
270
+ when: at least one novel finding has fix_complexity simple or moderate AND fix_approach is provided
271
+ - from: create_issue
272
+ to: notify
273
+ when: all novel findings have fix_complexity complex, OR no clear fix_approach
274
+ - from: skip
275
+ to: notify
276
+ - from: implement
277
+ to: create_pr
278
+ - from: create_pr
279
+ to: notify
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sweny-ai/core",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sweny": "./dist/cli/main.js"
@@ -42,7 +42,7 @@
42
42
  "dist"
43
43
  ],
44
44
  "scripts": {
45
- "build": "tsc",
45
+ "build": "tsc && cp src/workflows/*.yml dist/workflows/ && node scripts/build-workflow-browser.mjs",
46
46
  "typecheck": "tsc --noEmit",
47
47
  "test": "vitest run --exclude 'src/__tests__/integration/**'",
48
48
  "test:integration": "vitest run --config vitest.integration.config.ts"
@@ -1,11 +0,0 @@
1
- /**
2
- * Implement Workflow
3
- *
4
- * Given an issue, implement a fix and open a pull request.
5
- *
6
- * Compare: the previous version was 8 files, ~2000 lines.
7
- * This version is a DAG definition — Claude does the implementation
8
- * work at each node using the available skill tools.
9
- */
10
- import type { Workflow } from "../types.js";
11
- export declare const implementWorkflow: Workflow;
@@ -1,85 +0,0 @@
1
- /**
2
- * Implement Workflow
3
- *
4
- * Given an issue, implement a fix and open a pull request.
5
- *
6
- * Compare: the previous version was 8 files, ~2000 lines.
7
- * This version is a DAG definition — Claude does the implementation
8
- * work at each node using the available skill tools.
9
- */
10
- export const implementWorkflow = {
11
- id: "implement",
12
- name: "Implement Fix",
13
- description: "Implement a code fix for an issue and open a pull request",
14
- entry: "analyze",
15
- nodes: {
16
- analyze: {
17
- name: "Analyze Issue",
18
- instruction: `Read the issue details and understand what needs to be fixed:
19
-
20
- 1. Fetch the issue from the tracker (GitHub or Linear).
21
- 2. Read the relevant source files to understand the current code.
22
- 3. Identify the exact files and lines that need to change.
23
- 4. Plan the fix approach.
24
-
25
- Output a clear analysis of what needs to change and why.`,
26
- skills: ["github", "linear"],
27
- output: {
28
- type: "object",
29
- properties: {
30
- issue_summary: { type: "string" },
31
- files_to_change: { type: "array", items: { type: "string" } },
32
- fix_plan: { type: "string" },
33
- risk_level: { type: "string", enum: ["low", "medium", "high"] },
34
- },
35
- required: ["issue_summary", "fix_plan"],
36
- },
37
- },
38
- implement: {
39
- name: "Implement Fix",
40
- instruction: `Implement the planned fix:
41
-
42
- 1. Create a feature branch.
43
- 2. Make the necessary code changes.
44
- 3. Ensure changes are minimal and focused — fix the bug, nothing more.
45
- 4. Stage and commit with a clear commit message referencing the issue.
46
-
47
- If the fix is too risky or complex, explain why and skip.`,
48
- skills: ["github"],
49
- },
50
- create_pr: {
51
- name: "Open Pull Request",
52
- instruction: `Open a pull request for the fix:
53
-
54
- 1. Push the branch to the remote.
55
- 2. Create a PR with a clear title and description.
56
- 3. Reference the original issue in the PR body.
57
- 4. Add appropriate reviewers or labels if possible.
58
-
59
- If context.prTemplate is provided, use it as the format for the PR body. Otherwise use a clear structure with: Summary, Changes, Testing, and Related Issues.
60
-
61
- Return the PR URL.`,
62
- skills: ["github"],
63
- },
64
- notify: {
65
- name: "Notify",
66
- instruction: `Send a notification about the implementation result:
67
-
68
- 1. Include: issue reference, PR link, brief summary of changes.
69
- 2. Keep it concise — one message, not a wall of text.`,
70
- skills: ["slack", "notification"],
71
- },
72
- skip: {
73
- name: "Skip — Too Complex",
74
- instruction: `The fix was determined to be too complex or risky for automated implementation.
75
- Add a comment to the issue explaining what was found and why it needs manual attention.`,
76
- skills: ["github", "linear"],
77
- },
78
- },
79
- edges: [
80
- { from: "analyze", to: "implement", when: "Fix risk level is low or medium and a clear plan exists" },
81
- { from: "analyze", to: "skip", when: "Fix is too complex, risky, or unclear" },
82
- { from: "implement", to: "create_pr" },
83
- { from: "create_pr", to: "notify" },
84
- ],
85
- };
@@ -1,30 +0,0 @@
1
- /**
2
- * Content Generation Workflow
3
- *
4
- * A DAG that audits a Supabase-backed educational platform for content gaps,
5
- * generates high-quality content using Claude, validates it, and publishes it.
6
- *
7
- * Designed for solo operators bootstrapping educational SaaS platforms.
8
- * Uses Claude (via your existing subscription) for generation instead of
9
- * burning API credits on external AI gateways.
10
- *
11
- * @example
12
- * ```ts
13
- * import { execute, ClaudeClient, createSkillMap, supabase } from '@sweny-ai/core'
14
- * import { seedContentWorkflow } from '@sweny-ai/core/workflows'
15
- *
16
- * const skills = createSkillMap([supabase])
17
- * const claude = new ClaudeClient()
18
- *
19
- * const results = await execute(seedContentWorkflow, {
20
- * contentType: 'worksheet', // 'worksheet' | 'game' | 'lesson'
21
- * subject: 'math',
22
- * topic: 'fractions',
23
- * difficulty: 'easy',
24
- * gradeLevel: '3rd-grade',
25
- * count: 5,
26
- * }, { skills, claude })
27
- * ```
28
- */
29
- import type { Workflow } from "../types.js";
30
- export declare const seedContentWorkflow: Workflow;
@@ -1,217 +0,0 @@
1
- /**
2
- * Content Generation Workflow
3
- *
4
- * A DAG that audits a Supabase-backed educational platform for content gaps,
5
- * generates high-quality content using Claude, validates it, and publishes it.
6
- *
7
- * Designed for solo operators bootstrapping educational SaaS platforms.
8
- * Uses Claude (via your existing subscription) for generation instead of
9
- * burning API credits on external AI gateways.
10
- *
11
- * @example
12
- * ```ts
13
- * import { execute, ClaudeClient, createSkillMap, supabase } from '@sweny-ai/core'
14
- * import { seedContentWorkflow } from '@sweny-ai/core/workflows'
15
- *
16
- * const skills = createSkillMap([supabase])
17
- * const claude = new ClaudeClient()
18
- *
19
- * const results = await execute(seedContentWorkflow, {
20
- * contentType: 'worksheet', // 'worksheet' | 'game' | 'lesson'
21
- * subject: 'math',
22
- * topic: 'fractions',
23
- * difficulty: 'easy',
24
- * gradeLevel: '3rd-grade',
25
- * count: 5,
26
- * }, { skills, claude })
27
- * ```
28
- */
29
- export const seedContentWorkflow = {
30
- id: "seed-content",
31
- name: "Content Generation Pipeline",
32
- description: "Audit content gaps, generate educational content, validate quality, and publish to Supabase",
33
- entry: "audit",
34
- nodes: {
35
- // ─── Step 1: Audit ─────────────────────────────────────
36
- audit: {
37
- name: "Audit Content Gaps",
38
- instruction: `You are auditing an educational platform's content library.
39
-
40
- Use supabase_count to check how many items exist for each combination of:
41
- - Content types: worksheets, games, lessons
42
- - Subjects: math, science, english, history, geography, economics, music, art, life-skills, foreign-language
43
- - Difficulties: beginner, easy, medium, hard
44
-
45
- Also check the input parameters — if the user specified a subject, topic, difficulty, and count,
46
- skip the full audit and just report what they want generated.
47
-
48
- Return a structured content plan: what to generate, how many, at what difficulty and grade level.
49
- Prioritize gaps where a subject has ZERO content of a given type.`,
50
- skills: ["supabase"],
51
- output: {
52
- type: "object",
53
- properties: {
54
- plan: {
55
- type: "array",
56
- items: {
57
- type: "object",
58
- properties: {
59
- contentType: { type: "string" },
60
- subject: { type: "string" },
61
- topic: { type: "string" },
62
- difficulty: { type: "string" },
63
- gradeLevel: { type: "string" },
64
- count: { type: "number" },
65
- reason: { type: "string" },
66
- },
67
- required: ["contentType", "subject", "topic", "difficulty", "count"],
68
- },
69
- },
70
- summary: { type: "string" },
71
- },
72
- required: ["plan", "summary"],
73
- },
74
- },
75
- // ─── Step 2: Generate ──────────────────────────────────
76
- generate: {
77
- name: "Generate Content",
78
- instruction: `You are an expert educator creating content for children ages 5-14.
79
-
80
- For each item in the content plan from the previous step, generate the content directly.
81
- The content must be high-quality, engaging, age-appropriate, and educationally sound.
82
-
83
- **For worksheets:**
84
- Generate a JSON array of problems. Each problem needs: "problem", "answer", "format" (answer-line | multiple-choice | write-on).
85
- Requirements:
86
- - Every answer MUST be correct. Double-check math, facts, spelling.
87
- - Problems must progress in difficulty within the set.
88
- - Use at least 2 different problem structures (e.g., equations + word problems for math).
89
- - Vary phrasing — no two problems should feel copy-pasted.
90
- - For the target grade level, use appropriate vocabulary and complexity.
91
-
92
- **For lessons:**
93
- Generate complete HTML + CSS + JS for an interactive lesson.
94
- Requirements:
95
- - Must have substantial educational content (not just a shell with navigation).
96
- - Include interactive elements: quizzes, click-to-reveal, drag-and-drop.
97
- - Must be visually engaging with colors, icons, and clear typography.
98
- - Include practice exercises with immediate feedback.
99
- - Minimum 5 teaching sections plus 2 practice activities.
100
-
101
- **For games:**
102
- Generate a description and educational requirements only (actual game code is generated
103
- by the platform's Phaser-based generator).
104
-
105
- Use supabase_insert to write each piece of content to the appropriate table.
106
-
107
- Table schemas:
108
- - worksheets: id (auto), title, subject, topic, difficulty, grade_level, num_questions, problems (jsonb), status='published', source='ai-seed'
109
- - lessons: id (auto), title, subject, difficulty, grade_level, lesson_type, html_code, css_code, js_code, status='published', source='ai-seed'
110
- - games: id (auto), title, subject, difficulty, grade_level, game_type, html_code, css_code, js_code, status='published', source='ai-seed'
111
-
112
- Return a summary of what was generated and inserted.`,
113
- skills: ["supabase"],
114
- output: {
115
- type: "object",
116
- properties: {
117
- generated: {
118
- type: "array",
119
- items: {
120
- type: "object",
121
- properties: {
122
- contentType: { type: "string" },
123
- title: { type: "string" },
124
- subject: { type: "string" },
125
- id: { type: "string" },
126
- status: { type: "string" },
127
- },
128
- },
129
- },
130
- totalGenerated: { type: "number" },
131
- errors: { type: "array", items: { type: "string" } },
132
- },
133
- required: ["generated", "totalGenerated"],
134
- },
135
- },
136
- // ─── Step 3: Validate ──────────────────────────────────
137
- validate: {
138
- name: "Validate Content Quality",
139
- instruction: `Review the content that was just generated and inserted.
140
-
141
- For each item, use supabase_query to fetch it back and verify:
142
-
143
- **Worksheets:**
144
- - Parse the problems JSON — are all answers correct?
145
- - Are problems diverse (not repetitive)?
146
- - Is difficulty appropriate for the stated grade level?
147
- - Are there the right number of questions?
148
-
149
- **Lessons:**
150
- - Is the HTML substantial (> 500 characters)?
151
- - Does it contain actual educational content (not just navigation shells)?
152
- - Are there interactive elements?
153
-
154
- **Games:**
155
- - Does the HTML contain a working game structure?
156
-
157
- Flag any issues. If critical issues are found (wrong answers, empty content),
158
- use supabase_update to set status='draft' and add a note.
159
-
160
- Return a quality report.`,
161
- skills: ["supabase"],
162
- output: {
163
- type: "object",
164
- properties: {
165
- totalReviewed: { type: "number" },
166
- passed: { type: "number" },
167
- flagged: { type: "number" },
168
- issues: {
169
- type: "array",
170
- items: {
171
- type: "object",
172
- properties: {
173
- id: { type: "string" },
174
- title: { type: "string" },
175
- issue: { type: "string" },
176
- severity: { type: "string" },
177
- action: { type: "string" },
178
- },
179
- },
180
- },
181
- summary: { type: "string" },
182
- },
183
- required: ["totalReviewed", "passed", "flagged", "summary"],
184
- },
185
- },
186
- // ─── Step 4: Report ────────────────────────────────────
187
- report: {
188
- name: "Generate Report",
189
- instruction: `Compile a final report of the content generation run.
190
-
191
- Include:
192
- - Total content generated by type and subject
193
- - Quality validation results
194
- - Any issues found and actions taken
195
- - Recommendations for next content generation run (what gaps remain)
196
-
197
- Format as a clean markdown summary that a solo operator can scan in 30 seconds.`,
198
- skills: [],
199
- output: {
200
- type: "object",
201
- properties: {
202
- markdown: { type: "string" },
203
- nextPriorities: {
204
- type: "array",
205
- items: { type: "string" },
206
- },
207
- },
208
- required: ["markdown"],
209
- },
210
- },
211
- },
212
- edges: [
213
- { from: "audit", to: "generate" },
214
- { from: "generate", to: "validate" },
215
- { from: "validate", to: "report" },
216
- ],
217
- };
@@ -1,18 +0,0 @@
1
- /**
2
- * Triage Workflow
3
- *
4
- * Investigate a production alert → gather context → determine root cause →
5
- * create/update issue → implement fix → open PR → notify team.
6
- *
7
- * Provider-agnostic: nodes list all compatible skills per category.
8
- * The executor uses whichever skills are configured. Pre-execution
9
- * validation ensures required categories have at least one provider.
10
- *
11
- * Categories used:
12
- * git: github (+ bitbucket, gitlab in future)
13
- * observability: sentry, datadog, betterstack (+ aws, pagerduty in future)
14
- * tasks: linear, github (issues) (+ jira in future)
15
- * notification: slack, notification (discord/teams/webhook)
16
- */
17
- import type { Workflow } from "../types.js";
18
- export declare const triageWorkflow: Workflow;
@@ -1,207 +0,0 @@
1
- /**
2
- * Triage Workflow
3
- *
4
- * Investigate a production alert → gather context → determine root cause →
5
- * create/update issue → implement fix → open PR → notify team.
6
- *
7
- * Provider-agnostic: nodes list all compatible skills per category.
8
- * The executor uses whichever skills are configured. Pre-execution
9
- * validation ensures required categories have at least one provider.
10
- *
11
- * Categories used:
12
- * git: github (+ bitbucket, gitlab in future)
13
- * observability: sentry, datadog, betterstack (+ aws, pagerduty in future)
14
- * tasks: linear, github (issues) (+ jira in future)
15
- * notification: slack, notification (discord/teams/webhook)
16
- */
17
- export const triageWorkflow = {
18
- id: "triage",
19
- name: "Alert Triage",
20
- description: "Investigate a production alert, determine root cause, create an issue, implement a fix, and notify the team",
21
- entry: "prepare",
22
- nodes: {
23
- prepare: {
24
- name: "Load Rules & Context",
25
- instruction: `You are preparing for a triage workflow. Your job is to fetch and review any knowledge documents listed in the input.
26
-
27
- 1. Check input for \`rules_urls\` and \`context_urls\` arrays.
28
- 2. For each URL, fetch its content:
29
- - Linear document URLs → use the Linear MCP tools (get_document or search_documentation)
30
- - Other HTTP URLs → fetch directly
31
- 3. Summarize the key rules and context that downstream workflow nodes should follow.
32
- 4. Output the consolidated information so it's available to all subsequent steps.
33
-
34
- If there are no URLs to fetch, just pass through — this step is a no-op.`,
35
- skills: ["linear"],
36
- },
37
- gather: {
38
- name: "Gather Context",
39
- instruction: `You are investigating a production alert. Gather all relevant context using the available tools:
40
-
41
- 1. **Observability**: Pull error details, stack traces, recent logs, metrics, and active incidents around the time of the alert. Use whichever observability tools are available to you.
42
- 2. **Source control**: Check recent commits, pull requests, and deploys that might be related.
43
- 3. **Issue tracker**: Search for similar past issues or known problems.
44
-
45
- Be thorough — the investigation step depends on complete context. Use every tool available to you.`,
46
- skills: ["github", "sentry", "datadog", "betterstack", "linear"],
47
- },
48
- investigate: {
49
- name: "Root Cause Analysis",
50
- instruction: `Based on the gathered context, classify every distinct issue you found into one of two buckets: **novel** or **duplicate**.
51
-
52
- For EACH issue found:
53
- 1. Identify the root cause and affected code/service.
54
- 2. Assess severity: critical (service down), high (major feature broken), medium (degraded), low (cosmetic/minor).
55
- 3. Assess fix complexity: "simple" (a few lines, clear change), "moderate" (multiple files but well-understood), or "complex" (architectural, risky, or unclear).
56
- 4. **Novelty check (REQUIRED):** Search the issue tracker for existing issues (BOTH open AND closed) that cover the same root cause, error pattern, or affected service. Use github_search_issues and/or linear_search_issues with multiple keyword variations.
57
- - A match = same root cause, same error message/pattern, or a human would call it "the same bug."
58
- - If matched → it's a **duplicate**. Record the existing issue ID.
59
- - If no match → it's **novel**.
60
-
61
- **Output rules:**
62
- - \`findings\`: array of ALL issues found (both novel and duplicate).
63
- - \`novel_count\`: how many findings are novel (not duplicates).
64
- - \`highest_severity\`: the highest severity across ALL findings.
65
- - \`recommendation\`: what should happen next.
66
-
67
- Downstream nodes will act ONLY on novel findings. Duplicates will be +1'd automatically.`,
68
- skills: ["github", "linear"],
69
- output: {
70
- type: "object",
71
- properties: {
72
- findings: {
73
- type: "array",
74
- items: {
75
- type: "object",
76
- properties: {
77
- title: { type: "string", description: "Short description of the issue" },
78
- root_cause: { type: "string" },
79
- severity: { type: "string", enum: ["critical", "high", "medium", "low"] },
80
- affected_services: { type: "array", items: { type: "string" } },
81
- is_duplicate: { type: "boolean" },
82
- duplicate_of: { type: "string", description: "Existing issue ID/URL if duplicate" },
83
- fix_approach: { type: "string" },
84
- fix_complexity: { type: "string", enum: ["simple", "moderate", "complex"] },
85
- },
86
- required: ["title", "root_cause", "severity", "is_duplicate"],
87
- },
88
- },
89
- novel_count: { type: "number", description: "Count of novel (non-duplicate) findings" },
90
- highest_severity: { type: "string", enum: ["critical", "high", "medium", "low"] },
91
- recommendation: { type: "string" },
92
- },
93
- required: ["findings", "novel_count", "highest_severity", "recommendation"],
94
- },
95
- },
96
- create_issue: {
97
- name: "Create Issues & Triage Duplicates",
98
- instruction: `Process ALL findings from the investigation. The findings array contains both novel and duplicate issues.
99
-
100
- **For each NOVEL finding** (is_duplicate = false):
101
- 1. Create a new issue with a clear, actionable title.
102
- 2. Include: root cause, severity, affected services, reproduction steps, and recommended fix.
103
- 3. Add appropriate labels (bug, severity level, affected service).
104
- 4. Link to relevant commits, PRs, or existing issues.
105
-
106
- **For each DUPLICATE finding** (is_duplicate = true):
107
- 1. Find the existing issue (check duplicate_of field).
108
- 2. Check the issue's comments — if the most recent comment is already from SWEny (contains "+1") within the last 24 hours, skip adding another comment.
109
- 3. Otherwise add a SHORT comment: "+1 — seen again {UTC timestamp}. {one sentence of new context}." (Keep it under 2 lines. No markdown headers, no emoji, no formatting.)
110
- 4. If the existing issue is closed/done, reopen it.
111
-
112
- If context.issueTemplate is provided, use it as the format for new issue bodies. Otherwise use a clear structure with: Summary, Root Cause, Impact, Steps to Reproduce, and Recommended Fix.
113
-
114
- Use whichever issue tracker is available to you. Output the created/updated issue identifiers.`,
115
- skills: ["linear", "github"],
116
- },
117
- skip: {
118
- name: "Skip — All Duplicates or Low Priority",
119
- instruction: `Every finding from the investigation was either a duplicate or low-priority. No new issues need to be created.
120
-
121
- For each **duplicate** finding (check the findings array for items where is_duplicate = true):
122
- 1. Find the existing issue (check duplicate_of field).
123
- 2. Check the issue's comments — if the most recent comment is already from SWEny (contains "+1") within the last 24 hours, skip adding another comment.
124
- 3. Otherwise add a SHORT comment: "+1 — seen again {UTC timestamp}. {one sentence of new context}." (Keep it under 2 lines. No markdown headers, no emoji, no formatting.)
125
- 4. If the issue is closed/done, reopen it.
126
-
127
- For **low priority** findings, log a brief note about why they were skipped.`,
128
- skills: ["linear", "github"],
129
- },
130
- implement: {
131
- name: "Implement Fix",
132
- instruction: `Implement the fix identified during investigation:
133
-
134
- 1. Create a feature branch from the base branch (check context for baseBranch, default "main").
135
- 2. Read the relevant source files to understand the current code.
136
- 3. Make the necessary code changes — fix the bug, nothing more.
137
- 4. Run any existing tests if available to verify the fix doesn't break anything.
138
- 5. Stage and commit with a clear commit message referencing the issue.
139
-
140
- Keep changes minimal and focused. Do not refactor surrounding code or add unrelated improvements.
141
-
142
- If the fix turns out to be more complex than expected, stop and explain why — do not force a bad fix.`,
143
- skills: ["github"],
144
- },
145
- create_pr: {
146
- name: "Open Pull Request",
147
- instruction: `Open a pull request for the fix:
148
-
149
- 1. Push the branch to the remote.
150
- 2. Create a PR with a clear title referencing the issue (e.g. "[OFF-1020] fix: guard empty pdf_texts before access").
151
- 3. In the PR body, include: summary of the bug, what the fix does, and a link to the issue.
152
- 4. Add appropriate labels if available.
153
-
154
- If context.prTemplate is provided, use it as the format for the PR body. Otherwise use a clear structure with: Summary, Changes, Testing, and Related Issues.
155
-
156
- Return the PR URL and number.`,
157
- skills: ["github"],
158
- },
159
- notify: {
160
- name: "Notify Team",
161
- instruction: `Send a notification summarizing the triage result:
162
-
163
- 1. Include: alert summary, severity, root cause (1-2 sentences), and links to any created issues or PRs.
164
- 2. For critical/high severity, make the notification urgent.
165
- 3. For medium/low, a standard notification is fine.
166
-
167
- Use whichever notification channel is available to you.`,
168
- skills: ["slack", "notification"],
169
- },
170
- },
171
- edges: [
172
- // prepare → gather (always)
173
- { from: "prepare", to: "gather" },
174
- // gather → investigate (always)
175
- { from: "gather", to: "investigate" },
176
- // investigate → create_issue (novel findings worth acting on)
177
- {
178
- from: "investigate",
179
- to: "create_issue",
180
- when: "novel_count is greater than 0 AND highest_severity is medium or higher",
181
- },
182
- // investigate → skip (everything is a duplicate or low priority)
183
- {
184
- from: "investigate",
185
- to: "skip",
186
- when: "novel_count is 0, OR highest_severity is low",
187
- },
188
- // create_issue → implement (novel findings have a clear, feasible fix)
189
- {
190
- from: "create_issue",
191
- to: "implement",
192
- when: "at least one novel finding has fix_complexity simple or moderate AND fix_approach is provided",
193
- },
194
- // create_issue → notify (fixes too complex)
195
- {
196
- from: "create_issue",
197
- to: "notify",
198
- when: "all novel findings have fix_complexity complex, OR no clear fix_approach",
199
- },
200
- // skip → notify (nothing to implement — all duplicates +1'd or low priority)
201
- { from: "skip", to: "notify" },
202
- // implement → create_pr (always after successful implementation)
203
- { from: "implement", to: "create_pr" },
204
- // create_pr → notify (always)
205
- { from: "create_pr", to: "notify" },
206
- ],
207
- };