guild-agents 1.4.0 → 2.0.0
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.
- package/README.md +69 -68
- package/bin/guild.js +4 -85
- package/package.json +2 -2
- package/src/commands/doctor.js +11 -33
- package/src/commands/init.js +1 -1
- package/src/templates/agents/advisor.md +0 -1
- package/src/templates/agents/developer.md +2 -2
- package/src/templates/agents/qa.md +1 -1
- package/src/templates/agents/tech-lead.md +2 -2
- package/src/templates/skills/build-feature/SKILL.md +59 -117
- package/src/templates/skills/build-feature/evals/evals.json +3 -4
- package/src/templates/skills/council/SKILL.md +6 -16
- package/src/templates/skills/council/evals/evals.json +3 -13
- package/src/templates/skills/create-pr/SKILL.md +2 -5
- package/src/templates/skills/guild-specialize/SKILL.md +2 -9
- package/src/templates/skills/qa-cycle/SKILL.md +0 -7
- package/src/templates/skills/re-specialize/SKILL.md +0 -3
- package/src/templates/skills/session-end/SKILL.md +77 -30
- package/src/templates/skills/session-start/SKILL.md +51 -20
- package/src/utils/eval-runner.js +2 -8
- package/src/utils/generators.js +3 -4
- package/src/utils/skill-parser.js +83 -0
- package/src/utils/trigger-runner.js +1 -1
- package/src/commands/logs.js +0 -63
- package/src/commands/reset-learnings.js +0 -44
- package/src/commands/run.js +0 -105
- package/src/commands/stats.js +0 -147
- package/src/templates/agents/db-migration.md +0 -51
- package/src/templates/agents/learnings-extractor.md +0 -49
- package/src/templates/agents/platform-expert.md +0 -92
- package/src/templates/agents/product-owner.md +0 -52
- package/src/templates/skills/dev-flow/SKILL.md +0 -83
- package/src/templates/skills/dev-flow/evals/evals.json +0 -36
- package/src/templates/skills/dev-flow/evals/triggers.json +0 -16
- package/src/templates/skills/new-feature/SKILL.md +0 -119
- package/src/templates/skills/new-feature/evals/evals.json +0 -41
- package/src/templates/skills/new-feature/evals/triggers.json +0 -16
- package/src/templates/skills/review/SKILL.md +0 -97
- package/src/templates/skills/review/evals/evals.json +0 -43
- package/src/templates/skills/review/evals/triggers.json +0 -16
- package/src/templates/skills/status/SKILL.md +0 -100
- package/src/templates/skills/status/evals/evals.json +0 -40
- package/src/templates/skills/status/evals/triggers.json +0 -16
- package/src/templates/skills/verify/SKILL.md +0 -114
- package/src/templates/skills/verify/evals/triggers.json +0 -16
- package/src/utils/accounting.js +0 -139
- package/src/utils/dispatch-protocol.js +0 -74
- package/src/utils/dispatch.js +0 -172
- package/src/utils/executor.js +0 -183
- package/src/utils/learnings-io.js +0 -76
- package/src/utils/learnings.js +0 -204
- package/src/utils/orchestrator-io.js +0 -356
- package/src/utils/orchestrator.js +0 -590
- package/src/utils/pricing.js +0 -28
- package/src/utils/providers/claude-code.js +0 -43
- package/src/utils/skill-loader.js +0 -83
- package/src/utils/trace.js +0 -400
- package/src/utils/workflow-parser.js +0 -225
|
@@ -8,32 +8,34 @@ workflow:
|
|
|
8
8
|
- id: gather-state
|
|
9
9
|
role: system
|
|
10
10
|
intent: "Analyze current work state: task in progress, pipeline phase, modified files, session commits."
|
|
11
|
-
commands: [git status, git log --oneline -10]
|
|
12
11
|
produces: [work-state, modified-files, session-commits]
|
|
13
12
|
- id: update-session
|
|
14
13
|
role: system
|
|
15
|
-
intent: "Write
|
|
14
|
+
intent: "Write ephemeral state (task, branch, phase, next steps) to SESSION.md."
|
|
16
15
|
requires: [work-state, modified-files, session-commits]
|
|
17
16
|
produces: [session-update]
|
|
18
17
|
gate: true
|
|
18
|
+
- id: save-memory
|
|
19
|
+
role: system
|
|
20
|
+
intent: "Save durable learnings (decisions, lessons, references) to Claude Code memory files if any emerged this session."
|
|
21
|
+
requires: [session-update]
|
|
22
|
+
produces: [memory-update]
|
|
19
23
|
- id: commit-wip
|
|
20
24
|
role: system
|
|
21
25
|
intent: "Create WIP checkpoint commit if uncommitted changes exist."
|
|
22
|
-
commands: [git add -A, git commit -m "wip: session paused"]
|
|
23
26
|
requires: [modified-files]
|
|
24
27
|
produces: [wip-commit]
|
|
25
|
-
condition: has-uncommitted-changes
|
|
26
28
|
- id: confirm
|
|
27
29
|
role: system
|
|
28
|
-
intent: "Confirm SESSION.md updated, WIP committed, safe to close."
|
|
29
|
-
requires: [session-update]
|
|
30
|
+
intent: "Confirm SESSION.md updated, memory saved, WIP committed, safe to close."
|
|
31
|
+
requires: [session-update, memory-update]
|
|
30
32
|
produces: [confirmation]
|
|
31
33
|
gate: true
|
|
32
34
|
---
|
|
33
35
|
|
|
34
36
|
# Session End
|
|
35
37
|
|
|
36
|
-
Saves the current work state to SESSION.md
|
|
38
|
+
Saves the current work state to SESSION.md (ephemeral) and durable learnings to Claude Code memory (long-term). Run this skill before closing your work session.
|
|
37
39
|
|
|
38
40
|
## When to use
|
|
39
41
|
|
|
@@ -44,6 +46,17 @@ Saves the current work state to SESSION.md so it can be resumed in the next sess
|
|
|
44
46
|
|
|
45
47
|
`/session-end`
|
|
46
48
|
|
|
49
|
+
## Two persistence layers
|
|
50
|
+
|
|
51
|
+
This skill writes to two complementary systems:
|
|
52
|
+
|
|
53
|
+
| Layer | File | What goes here | Lifespan |
|
|
54
|
+
| --- | --- | --- | --- |
|
|
55
|
+
| **SESSION.md** | `SESSION.md` (project root) | Where you stopped: task, branch, phase, next steps | Overwritten each session |
|
|
56
|
+
| **Claude Code Memory** | `.claude/projects/*/memory/*.md` | What you learned: decisions, lessons, references | Persists across sessions |
|
|
57
|
+
|
|
58
|
+
**Rule of thumb:** if removing the information would make it hard to resume tomorrow, it goes in SESSION.md. If removing it would make you repeat a mistake in two weeks, it goes in memory.
|
|
59
|
+
|
|
47
60
|
## Process
|
|
48
61
|
|
|
49
62
|
### Step 1 — Gather current state
|
|
@@ -55,28 +68,61 @@ Analyze the current work state:
|
|
|
55
68
|
- What files were modified (via `git status`)
|
|
56
69
|
- What commits were made in this session
|
|
57
70
|
|
|
58
|
-
### Step 2 — Update SESSION.md
|
|
71
|
+
### Step 2 — Update SESSION.md (ephemeral state)
|
|
59
72
|
|
|
60
73
|
Update SESSION.md with the following information:
|
|
61
74
|
|
|
62
75
|
- **Date:** current date
|
|
63
76
|
- **Task in progress:** task name or "none"
|
|
64
77
|
- **GitHub Issue:** associated issue URL (if it exists)
|
|
65
|
-
- **
|
|
78
|
+
- **Branch:** current branch name
|
|
66
79
|
- **State:** concrete description of where the work left off
|
|
67
80
|
|
|
68
|
-
**Relevant context:**
|
|
69
|
-
|
|
70
|
-
- Decisions made in this session
|
|
71
|
-
- Problems encountered and how they were resolved
|
|
72
|
-
- Important information for resuming
|
|
73
|
-
|
|
74
81
|
**Next steps:**
|
|
75
82
|
|
|
76
83
|
- The 2-3 most important concrete actions when resuming
|
|
77
84
|
- Suggested skill to continue (e.g., "run /build-feature to continue from Phase 4")
|
|
78
85
|
|
|
79
|
-
|
|
86
|
+
**Technical context:**
|
|
87
|
+
|
|
88
|
+
- Version, test count, agent/skill counts — a snapshot that helps orient the next session
|
|
89
|
+
|
|
90
|
+
Do NOT put decisions, lessons, or references in SESSION.md — those belong in memory.
|
|
91
|
+
|
|
92
|
+
### Step 3 — Save durable learnings to Claude Code memory
|
|
93
|
+
|
|
94
|
+
Review the session for knowledge worth preserving long-term. For each item, write a memory file using the Write tool to the project's memory directory.
|
|
95
|
+
|
|
96
|
+
**What to save (only if something emerged this session):**
|
|
97
|
+
|
|
98
|
+
- **Decisions with lasting impact** → memory type `project`. Example: "Chose recursive execution for delegation because plan-expansion would break retry semantics on parent steps."
|
|
99
|
+
- **Lessons learned / corrections** → memory type `feedback`. Example: "npm audit fix resolves transitive vulnerabilities — don't chase individual Dependabot PRs when a single fix covers all."
|
|
100
|
+
- **New external references** → memory type `reference`. Example: "Release workflow logs at gh run view --job=ID --log."
|
|
101
|
+
|
|
102
|
+
**What NOT to save to memory:**
|
|
103
|
+
|
|
104
|
+
- Current task state (goes in SESSION.md)
|
|
105
|
+
- Code patterns or architecture (derivable from code)
|
|
106
|
+
- Git history (derivable from git log)
|
|
107
|
+
|
|
108
|
+
Use the standard memory frontmatter format:
|
|
109
|
+
|
|
110
|
+
```markdown
|
|
111
|
+
---
|
|
112
|
+
name: short-kebab-slug
|
|
113
|
+
description: "one-line summary"
|
|
114
|
+
metadata:
|
|
115
|
+
type: project|feedback|reference
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
Content with **Why:** and **How to apply:** lines for feedback/project types.
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Update `MEMORY.md` index if new memory files were created.
|
|
122
|
+
|
|
123
|
+
If nothing durable emerged this session, skip this step — not every session produces long-term learnings.
|
|
124
|
+
|
|
125
|
+
### Step 4 — Commit WIP if uncommitted work exists
|
|
80
126
|
|
|
81
127
|
If there are uncommitted changes, create a checkpoint commit:
|
|
82
128
|
|
|
@@ -87,25 +133,26 @@ git commit -m "wip: session paused — [brief description of current state]"
|
|
|
87
133
|
|
|
88
134
|
This ensures no work is lost between sessions. Never leave uncommitted changes across session boundaries.
|
|
89
135
|
|
|
136
|
+
### Step 5 — Confirm
|
|
137
|
+
|
|
138
|
+
Confirm to the user:
|
|
139
|
+
|
|
140
|
+
- SESSION.md updated with the current state
|
|
141
|
+
- Memory files saved (list which ones, if any)
|
|
142
|
+
- WIP committed (if applicable)
|
|
143
|
+
- Next steps recorded
|
|
144
|
+
- You can safely close the session
|
|
145
|
+
|
|
90
146
|
## Example Session
|
|
91
147
|
|
|
92
148
|
```text
|
|
93
149
|
User: /session-end
|
|
94
150
|
|
|
95
151
|
Saving session state...
|
|
96
|
-
Task: user-preferences
|
|
97
|
-
Phase: 4 — Implementation (in progress)
|
|
98
|
-
Files modified: 3 files
|
|
99
|
-
WIP committed: wip: session paused — user-preferences phase 4
|
|
100
|
-
|
|
101
|
-
SESSION.md updated. Safe to close.
|
|
102
|
-
```
|
|
103
152
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
153
|
+
SESSION.md: task=executor-v1.2, branch=feature/executor-v1.2, phase=complete
|
|
154
|
+
Memory: saved feedback/delegation-approach.md (recursive > plan-expansion)
|
|
155
|
+
WIP: no uncommitted changes
|
|
107
156
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- Next steps recorded
|
|
111
|
-
- You can safely close the session
|
|
157
|
+
Safe to close. Next session: create PR and update docs.
|
|
158
|
+
```
|
|
@@ -7,24 +7,22 @@ workflow:
|
|
|
7
7
|
steps:
|
|
8
8
|
- id: load-context
|
|
9
9
|
role: system
|
|
10
|
-
intent: "Read CLAUDE.md, SESSION.md, and
|
|
11
|
-
|
|
12
|
-
produces: [claude-md, session-md, project-md]
|
|
10
|
+
intent: "Read CLAUDE.md, SESSION.md, PROJECT.md, and Claude Code memory (MEMORY.md index + relevant memory files)."
|
|
11
|
+
produces: [claude-md, session-md, project-md, memory-context]
|
|
13
12
|
- id: detect-resumable
|
|
14
13
|
role: system
|
|
15
14
|
intent: "Check for wip: checkpoint commits on feature and fix branches."
|
|
16
|
-
commands: [git branch --list "feature/*" --list "fix/*", git log --oneline -1]
|
|
17
15
|
requires: [session-md]
|
|
18
16
|
produces: [resumable-branches, last-phase]
|
|
19
17
|
- id: present-state
|
|
20
18
|
role: system
|
|
21
|
-
intent: "Display
|
|
22
|
-
requires: [session-md, resumable-branches]
|
|
19
|
+
intent: "Display unified summary: ephemeral state from SESSION.md + durable context from memory."
|
|
20
|
+
requires: [session-md, memory-context, resumable-branches]
|
|
23
21
|
produces: [state-display]
|
|
24
22
|
gate: true
|
|
25
23
|
- id: suggest-continuation
|
|
26
24
|
role: system
|
|
27
|
-
intent: "Suggest appropriate skill to continue based on current state."
|
|
25
|
+
intent: "Suggest appropriate skill to continue based on current state and memory context."
|
|
28
26
|
requires: [state-display]
|
|
29
27
|
produces: [suggested-action]
|
|
30
28
|
gate: true
|
|
@@ -38,7 +36,7 @@ workflow:
|
|
|
38
36
|
|
|
39
37
|
# Session Start
|
|
40
38
|
|
|
41
|
-
Loads
|
|
39
|
+
Loads project context from two sources — SESSION.md (ephemeral work state) and Claude Code memory (durable learnings) — to resume where you left off. This is the first skill you should run when starting a work session.
|
|
42
40
|
|
|
43
41
|
## When to use
|
|
44
42
|
|
|
@@ -49,16 +47,36 @@ Loads the project context and resumes work from where it was left off in the pre
|
|
|
49
47
|
|
|
50
48
|
`/session-start`
|
|
51
49
|
|
|
50
|
+
## Two context sources
|
|
51
|
+
|
|
52
|
+
| Source | What it provides | Example |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| **SESSION.md** | Where you stopped: task, branch, phase, next steps | "Implementing executor v1.2, branch feature/executor, tests passing, next: write delegation tests" |
|
|
55
|
+
| **Claude Code Memory** | What you know: decisions, lessons, references | "Chose recursive execution for delegation because plan-expansion breaks retry semantics" |
|
|
56
|
+
|
|
57
|
+
Both are read and combined into a unified summary.
|
|
58
|
+
|
|
52
59
|
## Process
|
|
53
60
|
|
|
54
61
|
### Step 1 — Load context
|
|
55
62
|
|
|
56
|
-
Read
|
|
63
|
+
Read from both persistence layers:
|
|
64
|
+
|
|
65
|
+
**Ephemeral state (SESSION.md):**
|
|
57
66
|
|
|
58
67
|
- `CLAUDE.md` — project instructions, conventions, and rules
|
|
59
68
|
- `SESSION.md` — last session state, task in progress, next steps
|
|
60
69
|
- `PROJECT.md` — project identity, stack, configured agents
|
|
61
70
|
|
|
71
|
+
**Durable context (Claude Code memory):**
|
|
72
|
+
|
|
73
|
+
- Read `MEMORY.md` index from the project's memory directory
|
|
74
|
+
- Load relevant memory files, especially:
|
|
75
|
+
- `project` type — active decisions, ongoing initiatives
|
|
76
|
+
- `feedback` type — lessons learned, corrections, validated approaches
|
|
77
|
+
|
|
78
|
+
If either source is missing (no SESSION.md or no memory files), work with what's available.
|
|
79
|
+
|
|
62
80
|
### Step 2 — Detect resumable work
|
|
63
81
|
|
|
64
82
|
Check for `wip:` checkpoint commits on active branches:
|
|
@@ -71,16 +89,23 @@ done
|
|
|
71
89
|
|
|
72
90
|
If `wip:` commits are found, present them to the user with the phase they were in when interrupted.
|
|
73
91
|
|
|
74
|
-
### Step 3 — Present state
|
|
92
|
+
### Step 3 — Present unified state
|
|
93
|
+
|
|
94
|
+
Show a combined summary from both sources:
|
|
75
95
|
|
|
76
|
-
|
|
96
|
+
**From SESSION.md (where you stopped):**
|
|
77
97
|
|
|
78
98
|
- Date of the last session
|
|
79
99
|
- Task in progress (if any)
|
|
80
|
-
-
|
|
81
|
-
- Decisions made previously
|
|
100
|
+
- Branch and pipeline phase
|
|
82
101
|
- Recorded next steps
|
|
83
|
-
-
|
|
102
|
+
- Resumable pipelines (if wip: commits detected)
|
|
103
|
+
|
|
104
|
+
**From memory (what you know):**
|
|
105
|
+
|
|
106
|
+
- Recent project decisions that affect current work
|
|
107
|
+
- Relevant lessons or corrections from past sessions
|
|
108
|
+
- References to external systems or resources
|
|
84
109
|
|
|
85
110
|
### Step 4 — Suggest how to continue
|
|
86
111
|
|
|
@@ -89,12 +114,11 @@ If there is a task in progress:
|
|
|
89
114
|
- Show the task state
|
|
90
115
|
- Suggest continuing with the appropriate skill (e.g., `/build-feature` if in implementation)
|
|
91
116
|
- Show the next steps recorded in SESSION.md
|
|
117
|
+
- Flag any memory entries that are relevant to the current task
|
|
92
118
|
|
|
93
119
|
If there is no task in progress, suggest options:
|
|
94
120
|
|
|
95
121
|
- `/build-feature [description]` — to implement a new feature
|
|
96
|
-
- `/new-feature [name]` — to prepare the environment for a feature
|
|
97
|
-
- `/status` — to see the general project state
|
|
98
122
|
- `/council [question]` — to debate an important decision
|
|
99
123
|
|
|
100
124
|
### Step 5 — Update session
|
|
@@ -107,9 +131,16 @@ Update SESSION.md with the current date to record that the session has started.
|
|
|
107
131
|
User: /session-start
|
|
108
132
|
|
|
109
133
|
Loading context...
|
|
110
|
-
Last session: 2026-02-22
|
|
111
|
-
Task in progress: user-preferences (Phase 4 — Implementation)
|
|
112
|
-
Resumable: feature/user-preferences (wip: phase 3 complete)
|
|
113
134
|
|
|
114
|
-
|
|
135
|
+
SESSION.md: Last session 2026-05-25
|
|
136
|
+
Task: executor-v1.2 (complete)
|
|
137
|
+
Branch: main (clean)
|
|
138
|
+
Next steps: 1. MCP server 2. Agent Teams v2
|
|
139
|
+
|
|
140
|
+
Memory: 3 entries loaded
|
|
141
|
+
- project: "v1.5.0 shipped — 7 agents, 5-phase pipeline"
|
|
142
|
+
- feedback: "Recursive execution for delegation > plan-expansion"
|
|
143
|
+
- feedback: "npm audit fix resolves transitive vulns"
|
|
144
|
+
|
|
145
|
+
Suggested: Pick a backlog item — /build-feature or /council to decide.
|
|
115
146
|
```
|
package/src/utils/eval-runner.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { readFileSync, existsSync } from 'fs';
|
|
9
9
|
import { join, dirname } from 'path';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
|
-
import { parseSkill } from './
|
|
11
|
+
import { parseSkill } from './skill-parser.js';
|
|
12
12
|
|
|
13
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
14
|
const TEMPLATES_DIR = join(__dirname, '..', 'templates', 'skills');
|
|
@@ -63,13 +63,7 @@ export function evaluateAssertion(workflow, assertion) {
|
|
|
63
63
|
: { passed: false, evidence: `Step "${stepId}" requires [${step.requires.join(', ')}], missing "${dep}"` };
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
const step = workflow.steps.find(s => s.id === args);
|
|
68
|
-
if (!step) return { passed: false, evidence: `Step "${args}" not found` };
|
|
69
|
-
return step.parallel && step.parallel.length > 0
|
|
70
|
-
? { passed: true, evidence: `Step "${args}" is parallel with [${step.parallel.join(', ')}]` }
|
|
71
|
-
: { passed: false, evidence: `Step "${args}" has no parallel group` };
|
|
72
|
-
}
|
|
66
|
+
|
|
73
67
|
|
|
74
68
|
case 'gate-exists': {
|
|
75
69
|
const step = workflow.steps.find(s => s.id === args);
|
package/src/utils/generators.js
CHANGED
|
@@ -137,15 +137,14 @@ ${workspaceSection}
|
|
|
137
137
|
## Available skills
|
|
138
138
|
- /guild-specialize — enrich CLAUDE.md by exploring the actual project
|
|
139
139
|
- /build-feature — full development pipeline
|
|
140
|
-
- /new-feature — create branch and scaffold for a feature
|
|
141
140
|
- /create-pr — create a structured pull request from current branch
|
|
142
141
|
- /council — debate decisions with multiple agents
|
|
143
|
-
- /review — code review on the current diff
|
|
144
142
|
- /qa-cycle — QA + bugfix cycle
|
|
145
|
-
- /status — view project status
|
|
146
|
-
- /dev-flow — view current pipeline phase
|
|
147
143
|
- /session-start — load context and resume work
|
|
148
144
|
- /session-end — save state to SESSION.md
|
|
145
|
+
- /tdd — TDD red-green-refactor discipline
|
|
146
|
+
- /debug — systematic 4-phase debugging
|
|
147
|
+
- /re-specialize — incremental re-specialization of auto-generated zones
|
|
149
148
|
`;
|
|
150
149
|
|
|
151
150
|
writeFileSync('CLAUDE.md', content, 'utf8');
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skill-parser.js — Parses SKILL.md frontmatter for the eval system.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from workflow-parser.js. Contains only the parsing functions
|
|
5
|
+
* needed by eval-runner.js and trigger-runner.js.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import YAML from 'yaml';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extracts the raw YAML frontmatter string and body from markdown content.
|
|
12
|
+
* @param {string} content - Raw markdown content
|
|
13
|
+
* @returns {{ yaml: string, body: string } | null} Null if no frontmatter found
|
|
14
|
+
*/
|
|
15
|
+
export function extractFrontmatterBlock(content) {
|
|
16
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
17
|
+
if (!match) return null;
|
|
18
|
+
return {
|
|
19
|
+
yaml: match[1],
|
|
20
|
+
body: content.slice(match[0].length).trim(),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parses YAML frontmatter with full nested structure support.
|
|
26
|
+
* @param {string} yamlString - Raw YAML frontmatter
|
|
27
|
+
* @returns {object} Parsed frontmatter object
|
|
28
|
+
*/
|
|
29
|
+
export function parseYamlFrontmatter(yamlString) {
|
|
30
|
+
return YAML.parse(yamlString) || {};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function normalizeStep(raw) {
|
|
34
|
+
return {
|
|
35
|
+
id: raw.id,
|
|
36
|
+
role: raw.role,
|
|
37
|
+
intent: raw.intent,
|
|
38
|
+
requires: raw.requires || [],
|
|
39
|
+
produces: raw.produces || [],
|
|
40
|
+
modelTier: raw['model-tier'] || undefined,
|
|
41
|
+
gate: raw.gate || false,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Parses a SKILL.md file and extracts the skill definition.
|
|
47
|
+
* @param {string} content - Raw content of SKILL.md
|
|
48
|
+
* @returns {{ name: string, description: string, userInvocable: boolean, workflow: object|null, body: string }}
|
|
49
|
+
*/
|
|
50
|
+
export function parseSkill(content) {
|
|
51
|
+
const block = extractFrontmatterBlock(content);
|
|
52
|
+
if (!block) {
|
|
53
|
+
return {
|
|
54
|
+
name: '',
|
|
55
|
+
description: '',
|
|
56
|
+
userInvocable: false,
|
|
57
|
+
workflow: null,
|
|
58
|
+
body: content,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const frontmatter = parseYamlFrontmatter(block.yaml);
|
|
63
|
+
|
|
64
|
+
const skill = {
|
|
65
|
+
name: frontmatter.name || '',
|
|
66
|
+
description: frontmatter.description || '',
|
|
67
|
+
userInvocable: frontmatter['user-invocable'] === true,
|
|
68
|
+
workflow: null,
|
|
69
|
+
body: block.body,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (frontmatter.workflow) {
|
|
73
|
+
const raw = frontmatter.workflow;
|
|
74
|
+
skill.workflow = {
|
|
75
|
+
version: raw.version,
|
|
76
|
+
steps: Array.isArray(raw.steps)
|
|
77
|
+
? raw.steps.map(normalizeStep)
|
|
78
|
+
: [],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return skill;
|
|
83
|
+
}
|
|
@@ -6,7 +6,7 @@ import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
|
6
6
|
import { join, dirname } from 'path';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
import { rankSkills } from './trigger-matcher.js';
|
|
9
|
-
import { extractFrontmatterBlock, parseYamlFrontmatter } from './
|
|
9
|
+
import { extractFrontmatterBlock, parseYamlFrontmatter } from './skill-parser.js';
|
|
10
10
|
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
const TEMPLATES_DIR = join(__dirname, '..', 'templates', 'skills');
|
package/src/commands/logs.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* logs.js — View and manage Guild execution traces
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import * as p from '@clack/prompts';
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import { join } from 'node:path';
|
|
8
|
-
import { ensureProjectRoot } from '../utils/files.js';
|
|
9
|
-
import { listTraces, cleanTraces } from '../utils/trace.js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Runs the `guild logs` command.
|
|
13
|
-
*
|
|
14
|
-
* @param {'list'|'clean'} action - Subcommand to run
|
|
15
|
-
* @param {object} [options={}] - Options
|
|
16
|
-
* @param {string} [options.days='30'] - Days threshold for clean
|
|
17
|
-
* @param {boolean} [options.all] - Remove all traces
|
|
18
|
-
*/
|
|
19
|
-
export async function runLogs(action, options = {}) {
|
|
20
|
-
const root = ensureProjectRoot();
|
|
21
|
-
const tracesDir = join(root, '.claude', 'guild', 'traces');
|
|
22
|
-
|
|
23
|
-
if (action === 'clean') {
|
|
24
|
-
p.intro(chalk.bold.cyan('Guild — Clean Traces'));
|
|
25
|
-
|
|
26
|
-
let removed;
|
|
27
|
-
if (options.all) {
|
|
28
|
-
removed = cleanTraces(0, tracesDir);
|
|
29
|
-
} else {
|
|
30
|
-
const days = parseInt(options.days || '30', 10);
|
|
31
|
-
removed = cleanTraces(days, tracesDir);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
p.log.info(chalk.gray(`Removed ${removed} trace(s).`));
|
|
35
|
-
p.outro('');
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Default: list traces
|
|
40
|
-
p.intro(chalk.bold.cyan('Guild — Traces'));
|
|
41
|
-
|
|
42
|
-
const traces = listTraces(tracesDir);
|
|
43
|
-
|
|
44
|
-
if (traces.length === 0) {
|
|
45
|
-
p.log.info(chalk.gray('No traces found.'));
|
|
46
|
-
p.outro('');
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
for (const trace of traces) {
|
|
51
|
-
const date = trace.date !== 'unknown' ? new Date(trace.date).toLocaleString() : 'unknown';
|
|
52
|
-
const result = trace.result === 'pass' ? chalk.green('pass') :
|
|
53
|
-
trace.result === 'fail' ? chalk.red('fail') :
|
|
54
|
-
chalk.gray(trace.result || 'unknown');
|
|
55
|
-
|
|
56
|
-
p.log.info(` ${chalk.white.bold(trace.workflow)} ${result}`);
|
|
57
|
-
p.log.info(chalk.gray(` ${date} | level: ${trace.level}`));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
p.log.info('');
|
|
61
|
-
p.log.info(chalk.gray(`Total: ${traces.length} trace(s)`));
|
|
62
|
-
p.outro('');
|
|
63
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* reset-learnings.js — Resets the compound learnings file
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import * as p from '@clack/prompts';
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import { join } from 'path';
|
|
8
|
-
import { ensureProjectRoot } from '../utils/files.js';
|
|
9
|
-
import { learningsExist, deleteLearnings } from '../utils/learnings-io.js';
|
|
10
|
-
import { GUILD_LEARNINGS_PATH } from '../utils/learnings.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Runs the `guild reset-learnings` command.
|
|
14
|
-
* @param {object} [options]
|
|
15
|
-
* @param {boolean} [options.force] - Skip confirmation prompt
|
|
16
|
-
*/
|
|
17
|
-
export async function runResetLearnings(options = {}) {
|
|
18
|
-
const root = ensureProjectRoot();
|
|
19
|
-
const filePath = join(root, GUILD_LEARNINGS_PATH);
|
|
20
|
-
|
|
21
|
-
p.intro(chalk.bold.cyan('Guild — Reset Learnings'));
|
|
22
|
-
|
|
23
|
-
if (!learningsExist(filePath)) {
|
|
24
|
-
p.log.info('No learnings file found. Nothing to reset.');
|
|
25
|
-
p.outro('Done.');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!options.force) {
|
|
30
|
-
const confirmed = await p.confirm({
|
|
31
|
-
message: 'This will delete all accumulated learnings. Continue?',
|
|
32
|
-
initialValue: false,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
if (p.isCancel(confirmed) || !confirmed) {
|
|
36
|
-
p.cancel('Reset cancelled.');
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
deleteLearnings(filePath);
|
|
42
|
-
p.log.success(`${chalk.green('✓')} Learnings file deleted.`);
|
|
43
|
-
p.outro('Learnings have been reset. They will be regenerated on the next workflow execution.');
|
|
44
|
-
}
|
package/src/commands/run.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* run.js — Executes a skill workflow (or displays the plan in dry-run mode)
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import * as p from '@clack/prompts';
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
import { ensureProjectRoot } from '../utils/files.js';
|
|
8
|
-
import { orchestrate, finalizeWorkflowTrace } from '../utils/orchestrator-io.js';
|
|
9
|
-
import { execute } from '../utils/executor.js';
|
|
10
|
-
import { createClaudeCodeProvider } from '../utils/providers/claude-code.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Displays the execution plan without running it.
|
|
14
|
-
* @param {object} plan
|
|
15
|
-
* @param {object} dispatchInfoMap
|
|
16
|
-
*/
|
|
17
|
-
function displayPlan(plan, dispatchInfoMap) {
|
|
18
|
-
for (let i = 0; i < plan.groups.length; i++) {
|
|
19
|
-
const group = plan.groups[i];
|
|
20
|
-
const label = group.parallel ? `Group ${i + 1} (parallel)` : `Group ${i + 1}`;
|
|
21
|
-
p.log.step(chalk.bold(label));
|
|
22
|
-
|
|
23
|
-
for (const step of group.steps) {
|
|
24
|
-
const dispatch = dispatchInfoMap[step.id] || {};
|
|
25
|
-
const roleLabel = step.role === 'system' ? chalk.yellow('system') : chalk.blue(step.role);
|
|
26
|
-
const modelLabel = dispatch.model ? chalk.gray(` → ${dispatch.model}`) : '';
|
|
27
|
-
const gateLabel = step.gate ? chalk.red(' GATE') : '';
|
|
28
|
-
|
|
29
|
-
p.log.info(` ${chalk.white.bold(step.id)} ${roleLabel}${modelLabel}${gateLabel}`);
|
|
30
|
-
p.log.info(chalk.gray(` ${step.intent}`));
|
|
31
|
-
|
|
32
|
-
if (step.requires && step.requires.length > 0) {
|
|
33
|
-
p.log.info(chalk.gray(` requires: ${step.requires.join(', ')}`));
|
|
34
|
-
}
|
|
35
|
-
if (step.produces && step.produces.length > 0) {
|
|
36
|
-
p.log.info(chalk.gray(` produces: ${step.produces.join(', ')}`));
|
|
37
|
-
}
|
|
38
|
-
if (step.condition) {
|
|
39
|
-
p.log.info(chalk.gray(` condition: ${step.condition}`));
|
|
40
|
-
}
|
|
41
|
-
if (step.commands && step.commands.length > 0) {
|
|
42
|
-
p.log.info(chalk.gray(` commands: ${step.commands.join(', ')}`));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Runs the `guild run <skill>` command.
|
|
50
|
-
*
|
|
51
|
-
* @param {string} skillName - Name of the skill to run
|
|
52
|
-
* @param {string} [input=''] - Optional input text for the skill
|
|
53
|
-
* @param {object} [options={}] - Options
|
|
54
|
-
* @param {string} [options.profile='max'] - Model profile
|
|
55
|
-
* @param {boolean} [options.dryRun=false] - Show plan without executing
|
|
56
|
-
*/
|
|
57
|
-
export async function runRun(skillName, input = '', options = {}) {
|
|
58
|
-
const root = ensureProjectRoot();
|
|
59
|
-
const { profile = 'max', dryRun = false } = options;
|
|
60
|
-
|
|
61
|
-
p.intro(chalk.bold.cyan(' Guild — Run: ' + skillName + ' '));
|
|
62
|
-
|
|
63
|
-
const { plan, trace, dispatchInfoMap } = await orchestrate(skillName, input, {
|
|
64
|
-
profile,
|
|
65
|
-
projectRoot: root,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
p.log.info(chalk.gray(`Profile: ${profile} | Steps: ${plan.totalSteps}`));
|
|
69
|
-
|
|
70
|
-
if (dryRun) {
|
|
71
|
-
displayPlan(plan, dispatchInfoMap);
|
|
72
|
-
p.outro(chalk.gray('Plan generated (dry-run). No steps were executed.'));
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Real execution
|
|
77
|
-
const provider = createClaudeCodeProvider({ projectRoot: root });
|
|
78
|
-
|
|
79
|
-
const finalPlan = await execute(plan, dispatchInfoMap, {
|
|
80
|
-
provider,
|
|
81
|
-
skillBody: input,
|
|
82
|
-
trace,
|
|
83
|
-
projectRoot: root,
|
|
84
|
-
|
|
85
|
-
onStepStart(step, dispatch) {
|
|
86
|
-
const roleLabel = step.role === 'system' ? chalk.yellow('system') : chalk.blue(step.role);
|
|
87
|
-
const modelLabel = dispatch.model ? chalk.gray(` (${dispatch.model})`) : '';
|
|
88
|
-
p.log.step(`${chalk.bold(step.id)} ${roleLabel}${modelLabel}`);
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
onStepEnd(step, result) {
|
|
92
|
-
const icon = result.status === 'passed' ? chalk.green('✓') : chalk.red('✗');
|
|
93
|
-
p.log.info(` ${icon} ${result.status}`);
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Finalize trace
|
|
98
|
-
const { executionSummary } = finalizeWorkflowTrace(trace, finalPlan);
|
|
99
|
-
|
|
100
|
-
const statusLabel = finalPlan.status === 'completed'
|
|
101
|
-
? chalk.green('completed')
|
|
102
|
-
: chalk.red(finalPlan.status);
|
|
103
|
-
|
|
104
|
-
p.outro(`${statusLabel} | ${executionSummary}`);
|
|
105
|
-
}
|