@gethmy/mcp 3.7.0 → 3.9.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 +3 -3
- package/dist/cli.js +623 -157
- package/dist/index.js +228 -97
- package/dist/lib/api-client.js +181 -16
- package/dist/lib/config.js +110 -14
- package/dist/lib/oauth-refresh.js +110 -14
- package/dist/run-hook-cli.js +54 -0
- package/package.json +2 -2
- package/src/api-client.ts +91 -1
- package/src/config.ts +262 -14
- package/src/prompt-builder.ts +1 -1
- package/src/server.ts +70 -4
- package/src/skills.ts +6 -80
- package/src/tui/agent-instructions.ts +335 -0
- package/src/tui/setup.ts +144 -63
- package/src/tui/writer.ts +118 -2
package/src/skills.ts
CHANGED
|
@@ -11,86 +11,12 @@ import { getClient } from "./api-client.js";
|
|
|
11
11
|
import { areSkillsInstalled, isConfigured } from "./config.js";
|
|
12
12
|
import { loadHmyConfig } from "./hmy-config.js";
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
Start work on a Harmony card. Card reference: $ARGUMENTS
|
|
22
|
-
|
|
23
|
-
## 1. Find & Fetch Card
|
|
24
|
-
|
|
25
|
-
Parse the reference and fetch the card:
|
|
26
|
-
- \`#42\` or \`42\` → \`harmony_get_card\` with \`shortId: 42\`
|
|
27
|
-
- UUID → \`harmony_get_card\` with \`cardId\`
|
|
28
|
-
- Name/text → \`harmony_search_cards\` with \`query\`
|
|
29
|
-
|
|
30
|
-
## 2. Get Board State
|
|
31
|
-
|
|
32
|
-
Call \`harmony_get_board\` to get columns and labels. From the response:
|
|
33
|
-
- Find the "In Progress" (or "Progress") column ID
|
|
34
|
-
- Find the "agent" label ID
|
|
35
|
-
|
|
36
|
-
## 3. Setup Card for Work
|
|
37
|
-
|
|
38
|
-
Execute these in sequence:
|
|
39
|
-
1. \`harmony_move_card\` → Move to "In Progress" column
|
|
40
|
-
2. \`harmony_add_label_to_card\` → Add "agent" label
|
|
41
|
-
3. \`harmony_start_agent_session\`:
|
|
42
|
-
- \`cardId\`: Card UUID
|
|
43
|
-
- \`agentIdentifier\`: Your agent identifier
|
|
44
|
-
- \`agentName\`: Your agent name
|
|
45
|
-
- \`currentTask\`: "Analyzing card requirements"
|
|
46
|
-
|
|
47
|
-
## 4. Generate Work Prompt
|
|
48
|
-
|
|
49
|
-
Call \`harmony_generate_prompt\` with:
|
|
50
|
-
- \`cardId\` or \`shortId\` (+ \`projectId\` if using shortId)
|
|
51
|
-
- \`variant\`: Select based on task:
|
|
52
|
-
- \`"execute"\` (default) → Clear tasks, bug fixes, well-defined work
|
|
53
|
-
- \`"analysis"\` → Complex features, unclear requirements
|
|
54
|
-
- \`"draft"\` → Medium complexity, want feedback first
|
|
55
|
-
|
|
56
|
-
The generated prompt provides role framing, focus areas, subtasks, linked cards, and suggested outputs.
|
|
57
|
-
|
|
58
|
-
## 5. Display Card Summary
|
|
59
|
-
|
|
60
|
-
Show the user: Card title, short ID, role, priority, labels, due date, description, and subtasks.
|
|
61
|
-
|
|
62
|
-
## 6. Implement Solution
|
|
63
|
-
|
|
64
|
-
Work on the card following the generated prompt's guidance. Update progress at milestones:
|
|
65
|
-
- \`harmony_update_agent_progress\` with \`progressPercent\` (0-100), \`currentTask\`, \`status\`, \`blockers\`
|
|
66
|
-
|
|
67
|
-
**Progress checkpoints:** 20% (exploration), 50% (implementation), 80% (testing), 100% (done)
|
|
68
|
-
|
|
69
|
-
## 7. Complete Work
|
|
70
|
-
|
|
71
|
-
When finished:
|
|
72
|
-
1. \`harmony_end_agent_session\` with \`status: "completed"\`, \`progressPercent: 100\`
|
|
73
|
-
2. \`harmony_move_card\` to "Review" column
|
|
74
|
-
3. Summarize accomplishments
|
|
75
|
-
|
|
76
|
-
If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
|
|
77
|
-
|
|
78
|
-
## Key Tools Reference
|
|
79
|
-
|
|
80
|
-
**Cards:** \`harmony_get_card\` (by \`cardId\`, \`shortId\`, or \`shortIds\`), \`harmony_search_cards\`, \`harmony_create_card\`, \`harmony_update_card\`, \`harmony_move_card\`, \`harmony_delete_card\`, \`harmony_assign_card\`
|
|
81
|
-
|
|
82
|
-
**Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
|
|
83
|
-
|
|
84
|
-
**Labels:** \`harmony_add_label_to_card\`, \`harmony_remove_label_from_card\`, \`harmony_create_label\`
|
|
85
|
-
|
|
86
|
-
**Links:** \`harmony_add_link_to_card\`, \`harmony_remove_link_from_card\`, \`harmony_get_card_links\`
|
|
87
|
-
|
|
88
|
-
**Board:** \`harmony_get_board\`, \`harmony_list_projects\`, \`harmony_get_context\`, \`harmony_set_project_context\`
|
|
89
|
-
|
|
90
|
-
**Sessions:** \`harmony_start_agent_session\`, \`harmony_update_agent_progress\`, \`harmony_end_agent_session\`, \`harmony_get_agent_session\`
|
|
91
|
-
|
|
92
|
-
**AI:** \`harmony_generate_prompt\`, \`harmony_process_command\`
|
|
93
|
-
`;
|
|
14
|
+
// The workflow prompt for Codex / Cursor / Windsurf — which install via their
|
|
15
|
+
// own rule files rather than /v1/skills — used to live here. It moved to
|
|
16
|
+
// `tui/agent-instructions.ts` (#1124) so a test can read it alongside the
|
|
17
|
+
// AGENTS.md section and assert every tool it names is actually advertised.
|
|
18
|
+
// Import it from there; this module is not in the package `exports` map, so a
|
|
19
|
+
// re-export would have had no reachable consumer.
|
|
94
20
|
|
|
95
21
|
/**
|
|
96
22
|
* Shape of a /v1/skills/{name} response. Used by buildSkillFile + tests.
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The instruction text `hmy setup` installs into a project.
|
|
3
|
+
*
|
|
4
|
+
* Two strings, one job: tell an agent how to work a Harmony card correctly.
|
|
5
|
+
* They live here rather than inline in `setup.ts` so a test can read them —
|
|
6
|
+
* `setup-agent-files.test.ts` asserts every `harmony_*` name they mention is
|
|
7
|
+
* advertised by the server's `TOOLS` object. Nothing checked that before
|
|
8
|
+
* #1124, which is how `harmony_get_card_by_short_id` stayed in the installed
|
|
9
|
+
* `AGENTS.md` for four minor versions after 2.14.0 removed it.
|
|
10
|
+
*
|
|
11
|
+
* Both strings are governed by one rule: say only what the tool schemas do not
|
|
12
|
+
* already say. The schemas are in the agent's own tool listing, with live
|
|
13
|
+
* descriptions; restating them here creates a second source of truth that
|
|
14
|
+
* drifts, and that drift is this file's entire history.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The plan rule, in one wording for every runtime.
|
|
19
|
+
*
|
|
20
|
+
* A plan that prescribes the code is transcribed faithfully, defects included —
|
|
21
|
+
* so the rule has to reach the project, not only this repository. It ships three
|
|
22
|
+
* ways: this constant (Codex's `AGENTS.md` section and the Cursor / Windsurf
|
|
23
|
+
* rule files), and the `hmy-plan` skill body for Claude Code. It lives in one
|
|
24
|
+
* constant because a rule that is worded differently in three places is three
|
|
25
|
+
* rules, and only the differences get read.
|
|
26
|
+
*
|
|
27
|
+
* No heading of its own — each caller supplies the level its host file needs.
|
|
28
|
+
*/
|
|
29
|
+
export const HARMONY_PLAN_RULE = `**A plan says what must be true and why. It does not contain the code.** In it: the architecture
|
|
30
|
+
and technology decisions with their reasons, the data model and the API contracts, a short
|
|
31
|
+
signature or schema sketch wherever an interpretation gap would otherwise remain, and success
|
|
32
|
+
criteria a test can check. Not in it: function bodies, control flow, error handling, test code.
|
|
33
|
+
Detail follows risk — a throwaway script gets a rough plan, while auth, money, migrations and
|
|
34
|
+
anything security-relevant get their contracts and edge cases written out.
|
|
35
|
+
|
|
36
|
+
Code in a plan carries the authority of a plan and the quality of a draft that no compiler, test
|
|
37
|
+
or review has read, and an implementer transcribes it faithfully, defects included. So when the
|
|
38
|
+
plan and the code disagree, the code is the evidence: check it, record the decision as a comment,
|
|
39
|
+
and correct the plan as well as the code.`;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The Harmony section of a project's `AGENTS.md`. Written between the
|
|
43
|
+
* `<!-- harmony:start -->` / `<!-- harmony:end -->` markers by
|
|
44
|
+
* `mergeMarkdownSection`, so the rest of the file stays the project's.
|
|
45
|
+
*/
|
|
46
|
+
export const HARMONY_AGENTS_SECTION = `## Harmony
|
|
47
|
+
|
|
48
|
+
This project uses Harmony for task management. The \`harmony_*\` MCP tools are in your tool
|
|
49
|
+
listing with live schemas — read them there. This section covers only what the schemas do not say.
|
|
50
|
+
|
|
51
|
+
### Identify as yourself
|
|
52
|
+
|
|
53
|
+
Every session call takes \`agentIdentifier\` + \`agentName\`. Use your OWN, never a value copied
|
|
54
|
+
from this file. The board shows agents as teammates, so a session attributed to the wrong runtime
|
|
55
|
+
misattributes the work in front of the whole team.
|
|
56
|
+
|
|
57
|
+
Known values: \`claude-code\` / "Claude Code" · \`codex\` / "OpenAI Codex" · \`cursor\` / "Cursor" ·
|
|
58
|
+
\`claude-desktop\` / "Claude Desktop". If you are none of these, use your own name.
|
|
59
|
+
|
|
60
|
+
### Starting work — one call, not three
|
|
61
|
+
|
|
62
|
+
\`harmony_start_agent_session\` moves the card and adds the labels itself. Do not call
|
|
63
|
+
\`harmony_move_card\` or \`harmony_add_label_to_card\` first, and do not fetch the board for a
|
|
64
|
+
column id or a label id — both arguments match by name.
|
|
65
|
+
|
|
66
|
+
\`\`\`
|
|
67
|
+
harmony_start_agent_session({
|
|
68
|
+
cardId,
|
|
69
|
+
agentIdentifier, agentName, // your own
|
|
70
|
+
currentTask: "Reading the auth middleware to find the affected routes",
|
|
71
|
+
moveToColumn: "In Progress",
|
|
72
|
+
addLabels: ["agent"],
|
|
73
|
+
steerable: true, // only if you will poll for steering — see below
|
|
74
|
+
})
|
|
75
|
+
\`\`\`
|
|
76
|
+
|
|
77
|
+
**Then read the reply, because the setup half fails quietly.** \`movedTo\` names the column it
|
|
78
|
+
actually moved to and \`labelsAdded\` the labels it actually added; a miss leaves them null or
|
|
79
|
+
empty and raises no error. The column match is a case-insensitive **substring**, so a board with
|
|
80
|
+
"Ready for Review" ahead of "Review" can take the wrong one. If \`movedTo\` is null or not the
|
|
81
|
+
column you meant, call \`harmony_move_card\` — it matches exactly first and fails loudly, listing
|
|
82
|
+
the columns.
|
|
83
|
+
|
|
84
|
+
Keep the returned \`session.id\`; the steering poll needs it. Then call
|
|
85
|
+
\`harmony_generate_prompt\` for role framing and focus areas — \`variant\` is \`execute\`
|
|
86
|
+
(default), \`analysis\`, or \`draft\`.
|
|
87
|
+
|
|
88
|
+
### Progress — \`actions\` is what survives as evidence
|
|
89
|
+
|
|
90
|
+
On the card itself, \`progressPercent\` and \`currentTask\` each overwrite one field, so the live
|
|
91
|
+
status shows only your latest checkpoint. The timeline keeps more: a checkpoint that carries both
|
|
92
|
+
a \`progressPercent\` and a \`currentTask\` different from the last one leaves a row saying what you
|
|
93
|
+
were **about to do**, and **each entry in \`actions\` leaves a row saying what you actually did**.
|
|
94
|
+
Report four checkpoints with no \`actions\` and a two-hour run reads as four intentions and no
|
|
95
|
+
evidence.
|
|
96
|
+
|
|
97
|
+
Name what you DID since the last checkpoint: the file you edited and why, the gate you ran and
|
|
98
|
+
what it said, the approach you ruled out and on what evidence.
|
|
99
|
+
|
|
100
|
+
\`\`\`
|
|
101
|
+
harmony_update_agent_progress({
|
|
102
|
+
cardId, agentIdentifier, agentName,
|
|
103
|
+
progressPercent: 50,
|
|
104
|
+
currentTask: "Extracting refreshIfExpired() in auth.ts",
|
|
105
|
+
actions: [
|
|
106
|
+
{ description: "Read auth.ts and middleware/session.ts — the refresh path is duplicated in both, which is the actual bug" },
|
|
107
|
+
{ description: "Ruled out patching verifyToken(): three routes depend on its current behaviour" },
|
|
108
|
+
{ description: "Ran bun run lint — green, exit 0" },
|
|
109
|
+
],
|
|
110
|
+
})
|
|
111
|
+
\`\`\`
|
|
112
|
+
|
|
113
|
+
Three to six entries per checkpoint, one sentence each; past 512 characters an entry is silently truncated. Facts, not
|
|
114
|
+
intentions — one vague entry is worse than none. Checkpoints: 20% explored · 50% implementing ·
|
|
115
|
+
80% verifying · 100% done. \`currentTask\` is what you are doing now — never leave it generic.
|
|
116
|
+
|
|
117
|
+
### Steering and Stop
|
|
118
|
+
|
|
119
|
+
If you passed \`steerable: true\`, poll right after every progress update:
|
|
120
|
+
|
|
121
|
+
\`\`\`
|
|
122
|
+
harmony_get_pending_messages({ cardId, sessionId, sinceSeq }) // sinceSeq starts at 0
|
|
123
|
+
\`\`\`
|
|
124
|
+
|
|
125
|
+
Messages come back oldest first. Fold them into the next step and advance \`sinceSeq\` to the
|
|
126
|
+
largest \`seq\` returned, so each is handled exactly once.
|
|
127
|
+
|
|
128
|
+
Two flags come back and mean opposite things:
|
|
129
|
+
|
|
130
|
+
| flag | meaning | what to do |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| \`stopped: true\` | a human pressed Stop | **Terminal.** Make no further edits, commits, pushes, card moves, comments or progress writes. Report what is finished and where any uncommitted work lives. |
|
|
133
|
+
| \`sessionStale: true\` | your session id is no longer live — usually the inactivity sweep | **Nobody stopped you.** Carry on — with a new id. |
|
|
134
|
+
|
|
135
|
+
\`harmony_update_agent_progress\` reports the same two flags, and the recovery from a stale session
|
|
136
|
+
differs by which call told you:
|
|
137
|
+
|
|
138
|
+
- From the **progress** call, a replacement session has already been opened for you and inherited
|
|
139
|
+
the steering channel. Take the new \`session.id\` from that reply and keep going.
|
|
140
|
+
- From the **poll**, nothing was opened. Call \`harmony_start_agent_session\` yourself and poll
|
|
141
|
+
with the id it returns.
|
|
142
|
+
|
|
143
|
+
If the two flags ever disagree, the stop wins.
|
|
144
|
+
|
|
145
|
+
### Finishing
|
|
146
|
+
|
|
147
|
+
\`\`\`
|
|
148
|
+
harmony_end_agent_session({ cardId, status: "completed", progressPercent: 100, moveToColumn: "Review" })
|
|
149
|
+
\`\`\`
|
|
150
|
+
|
|
151
|
+
One call: it moves the card, and on \`status: "completed"\` it also removes the \`agent\` label. Use
|
|
152
|
+
\`status: "paused"\` when you stop mid-flight — that leaves the label on, which is what you want.
|
|
153
|
+
|
|
154
|
+
Attach a PR **after** the session end has moved the card, both ways: \`harmony_add_external_link\`
|
|
155
|
+
(durable — it survives a later description edit) and a \`PR: <url>\` line in the description.
|
|
156
|
+
|
|
157
|
+
### Writing a plan
|
|
158
|
+
|
|
159
|
+
${HARMONY_PLAN_RULE}
|
|
160
|
+
|
|
161
|
+
### Traps
|
|
162
|
+
|
|
163
|
+
- **A \`shortId\` is project-scoped, and the two ways it can miss are opposites.** With **no**
|
|
164
|
+
active project the number is resolved across every project you can reach, so it may come back
|
|
165
|
+
\`needsDisambiguation\` with \`candidates\` — ask which one is meant. With an active project the
|
|
166
|
+
number resolves only inside it, and a card that lives elsewhere fails with an error naming the
|
|
167
|
+
projects it is really in — switch with \`harmony_set_project_context\` or pass \`projectId\`.
|
|
168
|
+
Either way, check \`resolvedProject\` matches the card you meant before starting work.
|
|
169
|
+
- **Fetch many cards in one call:** \`harmony_get_card({ shortIds: [400, 401, 402] })\`, max 100.
|
|
170
|
+
- **Moving a card to a terminal column ends your session** — a column that marks cards done, or
|
|
171
|
+
one named \`done\`, \`completed\` or \`review\`. The response says \`sessionEnded\`.
|
|
172
|
+
- **Read \`harmony_get_comments\` before you act.** Steering messages do not include comments, and
|
|
173
|
+
a later comment outranks an earlier one it contradicts.
|
|
174
|
+
- **Report findings and decisions as comments, not description edits.** \`harmony_add_comment\`
|
|
175
|
+
takes a \`commentType\`: \`question\` and \`blocker\` signal that you need a human; \`decision\`,
|
|
176
|
+
\`finding\`, \`summary\`, \`progress\` and \`message\` are the rest.`;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The per-runtime workflow prompt installed as the Codex prompt file and the
|
|
180
|
+
* Cursor / Windsurf rule files. Rendered through `renderWorkflowPrompt`.
|
|
181
|
+
*/
|
|
182
|
+
export const HARMONY_WORKFLOW_PROMPT = `# Harmony Card Workflow
|
|
183
|
+
|
|
184
|
+
Work a Harmony card. Card reference: $ARGUMENTS
|
|
185
|
+
|
|
186
|
+
The \`harmony_*\` MCP tools are in your tool listing with live schemas — read them there. This
|
|
187
|
+
prompt covers only what the schemas do not say.
|
|
188
|
+
|
|
189
|
+
## 1. Fetch the card
|
|
190
|
+
|
|
191
|
+
- \`#42\` or \`42\` → \`harmony_get_card({ shortId: 42 })\`
|
|
192
|
+
- UUID → \`harmony_get_card({ cardId })\`
|
|
193
|
+
- A name or phrase → \`harmony_search_cards({ query })\`
|
|
194
|
+
- Several at once → \`harmony_get_card({ shortIds: [40, 41, 42] })\`, max 100
|
|
195
|
+
|
|
196
|
+
A \`shortId\` is project-scoped, and the two ways it can miss are opposites. With **no** active
|
|
197
|
+
project the number is resolved across every project you can reach, so it may come back
|
|
198
|
+
\`needsDisambiguation\` with \`candidates\` — ask which one is meant. With an active project the
|
|
199
|
+
number resolves only inside it, and a card that lives elsewhere fails with an error naming the
|
|
200
|
+
projects it is really in; switch with \`harmony_set_project_context\` or pass \`projectId\`.
|
|
201
|
+
Either way, check \`resolvedProject\` before you start.
|
|
202
|
+
|
|
203
|
+
Read \`harmony_get_comments\` too: a later comment outranks an earlier one it contradicts.
|
|
204
|
+
|
|
205
|
+
## 2. Start the session — one call, not three
|
|
206
|
+
|
|
207
|
+
\`harmony_start_agent_session\` moves the card and adds the labels itself. Do not call
|
|
208
|
+
\`harmony_move_card\` or \`harmony_add_label_to_card\` first, and do not fetch the board for a
|
|
209
|
+
column id or a label id — both arguments match by name.
|
|
210
|
+
|
|
211
|
+
\`\`\`
|
|
212
|
+
harmony_start_agent_session({
|
|
213
|
+
cardId,
|
|
214
|
+
agentIdentifier: "$AGENT_IDENTIFIER",
|
|
215
|
+
agentName: "$AGENT_NAME",
|
|
216
|
+
currentTask: "Reading the auth middleware to find the affected routes",
|
|
217
|
+
moveToColumn: "In Progress",
|
|
218
|
+
addLabels: ["agent"],
|
|
219
|
+
steerable: true,
|
|
220
|
+
})
|
|
221
|
+
\`\`\`
|
|
222
|
+
|
|
223
|
+
\`currentTask\` says what you are about to do, specifically. Never "Analyzing card requirements".
|
|
224
|
+
Keep the returned \`session.id\` — step 4 needs it.
|
|
225
|
+
|
|
226
|
+
**Read the reply, because the setup half fails quietly.** \`movedTo\` names the column it actually
|
|
227
|
+
moved to and \`labelsAdded\` the labels it actually added; a miss leaves them null or empty and
|
|
228
|
+
raises no error. The column match is a case-insensitive **substring**, so a board with "Ready for
|
|
229
|
+
Review" ahead of "Review" can take the wrong one. If \`movedTo\` is null or not the column you
|
|
230
|
+
meant, call \`harmony_move_card\` — it matches exactly first and fails loudly, listing the columns.
|
|
231
|
+
|
|
232
|
+
## 3. Get the work prompt
|
|
233
|
+
|
|
234
|
+
\`harmony_generate_prompt\` with \`cardId\` (or \`shortId\` plus \`projectId\`) and a \`variant\`:
|
|
235
|
+
\`execute\` (default) for well-defined work, \`analysis\` for unclear requirements, \`draft\` when
|
|
236
|
+
you want feedback on a design first. It returns role framing, focus areas, subtasks and links.
|
|
237
|
+
|
|
238
|
+
Then show the user the card: title, short id, priority, labels, due date, description, subtasks.
|
|
239
|
+
|
|
240
|
+
## 4. Implement, and check in at every milestone
|
|
241
|
+
|
|
242
|
+
Checkpoints: 20% explored · 50% implementing · 80% verifying · 100% done.
|
|
243
|
+
|
|
244
|
+
On the card itself, \`progressPercent\` and \`currentTask\` each overwrite one field, so the live
|
|
245
|
+
status shows only your latest checkpoint. The timeline keeps more: a checkpoint that carries both
|
|
246
|
+
a \`progressPercent\` and a \`currentTask\` different from the last one leaves a row saying what you
|
|
247
|
+
were **about to do**, and **each entry in \`actions\` leaves a row saying what you actually did** —
|
|
248
|
+
that is the evidence the team can still read afterwards.
|
|
249
|
+
|
|
250
|
+
\`\`\`
|
|
251
|
+
harmony_update_agent_progress({
|
|
252
|
+
cardId, agentIdentifier: "$AGENT_IDENTIFIER", agentName: "$AGENT_NAME",
|
|
253
|
+
progressPercent: 50,
|
|
254
|
+
currentTask: "Extracting refreshIfExpired() in auth.ts",
|
|
255
|
+
actions: [
|
|
256
|
+
{ description: "Read auth.ts and middleware/session.ts — the refresh path is duplicated in both, which is the actual bug" },
|
|
257
|
+
{ description: "Ruled out patching verifyToken(): three routes depend on its current behaviour" },
|
|
258
|
+
{ description: "Ran bun run lint — green, exit 0" },
|
|
259
|
+
],
|
|
260
|
+
status: "working", // or blocked / waiting / paused
|
|
261
|
+
blockers: [],
|
|
262
|
+
})
|
|
263
|
+
\`\`\`
|
|
264
|
+
|
|
265
|
+
Three to six entries per checkpoint, one sentence each; past 512 characters an entry is silently truncated. Say what you did,
|
|
266
|
+
not what you intend to do.
|
|
267
|
+
|
|
268
|
+
Right after each update, poll for steering:
|
|
269
|
+
|
|
270
|
+
\`\`\`
|
|
271
|
+
harmony_get_pending_messages({ cardId, sessionId, sinceSeq }) // sinceSeq starts at 0
|
|
272
|
+
\`\`\`
|
|
273
|
+
|
|
274
|
+
Fold any messages into the next step and advance \`sinceSeq\` to the largest \`seq\` returned. Two
|
|
275
|
+
flags come back and mean opposite things:
|
|
276
|
+
|
|
277
|
+
- \`stopped: true\` — a human pressed Stop. **Terminal.** Make no further edits, commits, pushes,
|
|
278
|
+
card moves, comments or progress writes; report what is finished and where any uncommitted work
|
|
279
|
+
lives.
|
|
280
|
+
- \`sessionStale: true\` — your session id is no longer live, usually the inactivity sweep. **Nobody stopped you.**
|
|
281
|
+
Carry on, with a new id: the **poll** opens nothing, so call \`harmony_start_agent_session\`
|
|
282
|
+
yourself; the **progress** call has already opened a replacement that inherited the steering
|
|
283
|
+
channel, so just take the new \`session.id\` from its reply.
|
|
284
|
+
|
|
285
|
+
If the two flags ever disagree, the stop wins.
|
|
286
|
+
|
|
287
|
+
Report findings and decisions with \`harmony_add_comment\` (\`commentType\`: \`question\` and
|
|
288
|
+
\`blocker\` signal that you need a human; \`decision\`, \`finding\`, \`summary\`, \`progress\`,
|
|
289
|
+
\`message\`), not by editing the card description.
|
|
290
|
+
|
|
291
|
+
## 5. Finish
|
|
292
|
+
|
|
293
|
+
\`\`\`
|
|
294
|
+
harmony_end_agent_session({ cardId, status: "completed", progressPercent: 100, moveToColumn: "Review" })
|
|
295
|
+
\`\`\`
|
|
296
|
+
|
|
297
|
+
One call: it moves the card, and on \`status: "completed"\` it also removes the \`agent\` label. Use
|
|
298
|
+
\`status: "paused"\` when you stop mid-flight — that leaves the label on, which is what you want.
|
|
299
|
+
|
|
300
|
+
Opened a PR? Attach it **after** the session end has moved the card, both ways:
|
|
301
|
+
\`harmony_add_external_link\` (durable — it survives a later description edit) and a
|
|
302
|
+
\`PR: <url>\` line in the description.
|
|
303
|
+
|
|
304
|
+
Then summarise what changed.
|
|
305
|
+
|
|
306
|
+
## Writing a plan
|
|
307
|
+
|
|
308
|
+
${HARMONY_PLAN_RULE}
|
|
309
|
+
|
|
310
|
+
## Worth knowing
|
|
311
|
+
|
|
312
|
+
- Moving a card to a terminal column ends your session — a column that marks cards done, or one
|
|
313
|
+
named \`done\`, \`completed\` or \`review\`. The response says \`sessionEnded\`.
|
|
314
|
+
- \`harmony_add_label_to_card\` and \`harmony_start_agent_session\`'s \`addLabels\` both CREATE a
|
|
315
|
+
label that does not exist yet. Check the spelling.
|
|
316
|
+
- \`harmony_add_comment\` works on any card you can see, including one you hold no session on.`;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Render the workflow prompt for one runtime.
|
|
320
|
+
*
|
|
321
|
+
* The placeholders are explicit tokens rather than prose. The previous version
|
|
322
|
+
* chained `.replace("Your agent identifier", …)` over the prompt text, which
|
|
323
|
+
* substitutes only the FIRST occurrence and no-ops silently the moment that
|
|
324
|
+
* exact sentence is reworded — so a prompt could ship telling Cursor to call
|
|
325
|
+
* itself "Your agent name" with nothing failing (#1124).
|
|
326
|
+
*/
|
|
327
|
+
export function renderWorkflowPrompt(opts: {
|
|
328
|
+
cardArgument: string;
|
|
329
|
+
agentIdentifier: string;
|
|
330
|
+
agentName: string;
|
|
331
|
+
}): string {
|
|
332
|
+
return HARMONY_WORKFLOW_PROMPT.replaceAll("$ARGUMENTS", opts.cardArgument)
|
|
333
|
+
.replaceAll("$AGENT_IDENTIFIER", opts.agentIdentifier)
|
|
334
|
+
.replaceAll("$AGENT_NAME", opts.agentName);
|
|
335
|
+
}
|