copilot-tap-extension 2.0.6 → 2.0.7
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 +6 -3
- package/dist/copilot-instructions.md +15 -9
- package/dist/extension.mjs +11 -10
- package/dist/skills/tap-goal/SKILL.md +116 -31
- package/dist/version.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -212,13 +212,15 @@ The prompt fires immediately, then re-fires after each idle period. It stops aft
|
|
|
212
212
|
|
|
213
213
|
**Work toward a goal autonomously**
|
|
214
214
|
|
|
215
|
-
Use `/tap-goal` to create
|
|
215
|
+
Use `/tap-goal` to create a goal loop that keeps advancing a concrete objective until it finishes, hits a blocker, or reaches its iteration budget. Goals are explicit completion contracts, control commands are user-owned, and the loop should stop itself only when the objective is actually complete, blocked, or budget-limited.
|
|
216
216
|
|
|
217
217
|
```
|
|
218
218
|
/tap-goal migrate the repo to the new API and keep going until tests pass
|
|
219
219
|
```
|
|
220
220
|
|
|
221
|
-
The skill creates a temporary
|
|
221
|
+
The skill creates a temporary PromptEmitter with a self-contained goal prompt. Conservative goals use an idle schedule; autopilot-style goals use a timed backoff schedule so the objective can keep nudging the session even when Copilot stays busy. Each iteration inspects its own emitter state, works against a six-part goal contract, records structured progress to its EventStream, validates when relevant, and stops the emitter when the goal is complete, blocked, or budget-limited.
|
|
222
|
+
|
|
223
|
+
A strong goal names the outcome, verification surface, constraints, boundaries, iteration policy, and blocked stop condition. Completion requires an evidence audit against concrete files, tests, logs, benchmark output, generated artifacts, or research evidence.
|
|
222
224
|
|
|
223
225
|
Goal loops default to 50 iterations unless you specify another budget.
|
|
224
226
|
|
|
@@ -228,7 +230,7 @@ Use `/tap-goal stop <name>` or `/tap-goal clear <name>` to stop a specific goal
|
|
|
228
230
|
|
|
229
231
|
Use `/tap-goal resume <objective>` to start a new loop from an objective. Stopped goal loops do not preserve resumable internal state; resuming creates a new emitter from the supplied objective.
|
|
230
232
|
|
|
231
|
-
Because `/tap-goal`
|
|
233
|
+
Because `/tap-goal` can use either idle or timed PromptEmitters, choose idle for conservative continuation and timed-autopilot mode for always-busy flows. Timed prompt deferrals do not consume the run budget; budget exhaustion still means "handoff needed," not success.
|
|
232
234
|
|
|
233
235
|
**Tune the filter live**
|
|
234
236
|
|
|
@@ -286,6 +288,7 @@ PLAN.md # ubiquitous language and design decisions
|
|
|
286
288
|
| [Provider guide](./docs/providers.md) | Add external tools to Copilot via the WebSocket provider interface |
|
|
287
289
|
| [Use cases and patterns](./docs/use-cases.md) | Recipes for deploy watchers, PR monitors, log tailers, and more |
|
|
288
290
|
| [Copilot SDK canvas surfaces](./docs/recipes/copilot-sdk-canvas.md) | Local SDK findings for extension-owned canvas UI surfaces |
|
|
291
|
+
| [Codex Goals lessons for tap-goal](./docs/recipes/codex-goals-for-tap-goal.md) | Goal-loop contract, evidence audit, and autopilot scheduling guidance |
|
|
289
292
|
| [Evals](./docs/evals.md) | Run or extend the automated test suite |
|
|
290
293
|
| [Copilot instructions](./src/copilot-instructions.md) | Understand or customize how the agent uses this extension |
|
|
291
294
|
| [Implementation plan](./PLAN.md) | Ubiquitous language and naming conventions for contributors |
|
|
@@ -145,20 +145,26 @@ If the work is mostly reasoning rather than data collection, prefer a PromptEmit
|
|
|
145
145
|
|
|
146
146
|
- prompt once for a background check (oneTime)
|
|
147
147
|
- prompt + `every="<interval>"` for a fixed maintenance loop (timed)
|
|
148
|
-
- prompt + `every="idle"` + `maxRuns` for autonomous goal loops with explicit iteration budgets (`/tap-goal`)
|
|
148
|
+
- prompt + `every="idle"` + `maxRuns` for conservative autonomous goal loops with explicit iteration budgets (`/tap-goal`)
|
|
149
|
+
- prompt + `everySchedule=[...]` + `maxRuns` for autopilot-compatible goals that need timed nudges while the session may stay busy
|
|
149
150
|
|
|
150
151
|
This is the closest analogue to Claude's session-scoped `/tap-loop` behavior in this extension.
|
|
151
152
|
|
|
152
153
|
For "keep working until done" requests, prefer `/tap-goal`: create an
|
|
153
|
-
|
|
154
|
-
budget
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
154
|
+
PromptEmitter with a self-contained goal prompt and an explicit `maxRuns`
|
|
155
|
+
budget. A strong goal is a six-part completion contract: outcome, verification
|
|
156
|
+
surface, constraints, boundaries, iteration policy, and blocked stop condition.
|
|
157
|
+
Goals must be explicit user requests; do not infer them from ordinary one-shot
|
|
158
|
+
tasks, and do not treat budget exhaustion as successful completion. Goal prompts
|
|
159
|
+
should self-steer by reading their own emitter state with `tap_list_emitters`,
|
|
160
|
+
switching into wrap-up mode when the remaining iteration budget is low, posting
|
|
161
|
+
structured iteration records to their EventStream with `tap_post`, and stopping
|
|
162
|
+
themselves when complete or blocked. Completion requires an evidence audit
|
|
163
|
+
against concrete files, tests, logs, benchmark output, or generated artifacts.
|
|
159
164
|
If the session may stay continuously busy (for example in autopilot-heavy
|
|
160
|
-
flows),
|
|
161
|
-
instead of relying on idle to trigger the next
|
|
165
|
+
flows), use a timed PromptEmitter with a backoff schedule such as
|
|
166
|
+
`everySchedule=["2m","5m","10m"]` instead of relying on idle to trigger the next
|
|
167
|
+
goal step.
|
|
162
168
|
|
|
163
169
|
## Borrow from the official SDK examples
|
|
164
170
|
|
package/dist/extension.mjs
CHANGED
|
@@ -4568,12 +4568,12 @@ function createEmitterTools(deps) {
|
|
|
4568
4568
|
properties: {
|
|
4569
4569
|
name: { type: "string", description: "Unique emitter name." },
|
|
4570
4570
|
command: { type: "string", description: "Shell command to run (creates a CommandEmitter). Output goes through EventFilter rules to determine whether lines are kept, surfaced, or injected. Use for log tailing, process monitoring, or any external command with stdout." },
|
|
4571
|
-
prompt: { type: "string", description: "Prompt to send to the agent (creates a PromptEmitter). Always injects \u2014 bypasses EventFilter entirely. Use for repeated agent tasks, status checks, or
|
|
4571
|
+
prompt: { type: "string", description: "Prompt to send to the agent (creates a PromptEmitter). Always injects \u2014 bypasses EventFilter entirely. Use for repeated agent tasks, status checks, simple messages, or autonomous goal loops." },
|
|
4572
4572
|
description: { type: "string", description: "Short summary." },
|
|
4573
4573
|
channel: { type: "string", description: "EventStream to receive accepted events." },
|
|
4574
4574
|
cwd: { type: "string", description: "Optional subdirectory relative to the session cwd. Absolute paths and paths that escape the session cwd are rejected." },
|
|
4575
|
-
every: { type: "string", description: "Optional repeat interval like 30s, 5m, 2h, or 1d (maximum about 24 days). Use 'idle' for
|
|
4576
|
-
everySchedule: { type: "array", minItems: 1, items: { type: "string" }, description: "Optional backoff schedule \u2014 an ordered non-empty list of interval strings (e.g. ['10s','20s','30s','1m','2m','5m','10m']; each maximum about 24 days). The emitter uses each interval in sequence, then repeats the last one forever. Overrides 'every' when provided. Cannot be 'idle' entries." },
|
|
4575
|
+
every: { type: "string", description: "Optional repeat interval like 30s, 5m, 2h, or 1d (maximum about 24 days). Use 'idle' for conservative prompt loops that re-run only when the session is idle. When omitted, commands run continuously and prompts run once." },
|
|
4576
|
+
everySchedule: { type: "array", minItems: 1, items: { type: "string" }, description: "Optional backoff schedule \u2014 an ordered non-empty list of interval strings (e.g. ['10s','20s','30s','1m','2m','5m','10m']; each maximum about 24 days). The emitter uses each interval in sequence, then repeats the last one forever. Overrides 'every' when provided. Cannot be 'idle' entries. Prefer this for autopilot-compatible goal loops that may need timed nudges while the session stays busy." },
|
|
4577
4577
|
lifespan: policyLifespanParameter(),
|
|
4578
4578
|
ownership: policyOwnershipParameter(),
|
|
4579
4579
|
scope: policyScopeParameter(),
|
|
@@ -4583,7 +4583,7 @@ function createEmitterTools(deps) {
|
|
|
4583
4583
|
eventFilter: EVENT_FILTER_PARAMETER_SCHEMA,
|
|
4584
4584
|
subscribe: { type: "boolean", description: "Whether to attach a session injector to the stream as part of emitter creation." },
|
|
4585
4585
|
delivery: { type: "string", description: "Session injector delivery mode. 'important'/'inject' only send inject-outcome lines, 'surface' surfaces surface outcomes and sends inject outcomes, 'all' surfaces all accepted lines while inject outcomes still push into the conversation, and 'keep'/'drop' store without proactive delivery." },
|
|
4586
|
-
maxRuns: { type: "integer", description: "Maximum number of iterations before the emitter
|
|
4586
|
+
maxRuns: { type: "integer", description: "Maximum number of real iterations before the emitter stops. Useful for idle and timed loops. For goal loops this is a budget limit, not proof that the objective is complete." },
|
|
4587
4587
|
force: policyForceParameter("emitter")
|
|
4588
4588
|
},
|
|
4589
4589
|
required: ["name"]
|
|
@@ -9003,7 +9003,7 @@ function buildCompleteMessage(state) {
|
|
|
9003
9003
|
return `Emitter '${state.name}' completed one run of ${state.emitterType} work.`;
|
|
9004
9004
|
}
|
|
9005
9005
|
if (state.maxRuns && state.runCount >= state.maxRuns) {
|
|
9006
|
-
return `Emitter '${state.name}'
|
|
9006
|
+
return `Emitter '${state.name}' reached its run budget (${state.runCount} of ${state.maxRuns} runs). This stops the emitter; goal-style loops must use their final evidence summary to decide whether the objective is complete.`;
|
|
9007
9007
|
}
|
|
9008
9008
|
return null;
|
|
9009
9009
|
}
|
|
@@ -9158,12 +9158,12 @@ function computeDeferredIterationTransition(currentState, state) {
|
|
|
9158
9158
|
};
|
|
9159
9159
|
}
|
|
9160
9160
|
function computeFailedIterationTransition(currentState, state, event, result) {
|
|
9161
|
-
if (isRunBudgetExhausted(state)) {
|
|
9162
|
-
return computeRunBudgetExhaustedTransition(currentState, state, event, result);
|
|
9163
|
-
}
|
|
9164
9161
|
if (result.deferred) {
|
|
9165
9162
|
return computeDeferredIterationTransition(currentState, state);
|
|
9166
9163
|
}
|
|
9164
|
+
if (isRunBudgetExhausted(state)) {
|
|
9165
|
+
return computeRunBudgetExhaustedTransition(currentState, state, event, result);
|
|
9166
|
+
}
|
|
9167
9167
|
if (state.runSchedule === RUN_SCHEDULE.ONE_TIME) {
|
|
9168
9168
|
return {
|
|
9169
9169
|
currentState,
|
|
@@ -9503,11 +9503,12 @@ async function runPromptIteration(emitter, context) {
|
|
|
9503
9503
|
} catch (error) {
|
|
9504
9504
|
const message = error?.message ?? String(error ?? "unknown error");
|
|
9505
9505
|
const sessionNotAttached = isSessionNotAttachedMessage(message);
|
|
9506
|
+
const deferred = sessionNotAttached || (emitter.runSchedule === RUN_SCHEDULE.TIMED || emitter.runSchedule === RUN_SCHEDULE.IDLE) && /\bsession\.idle\b/i.test(message);
|
|
9506
9507
|
return {
|
|
9507
9508
|
ok: false,
|
|
9508
9509
|
error: message,
|
|
9509
|
-
deferred
|
|
9510
|
-
consumeRun:
|
|
9510
|
+
deferred,
|
|
9511
|
+
consumeRun: deferred ? false : true,
|
|
9511
9512
|
deferredReason: sessionNotAttached ? "session-not-attached" : null
|
|
9512
9513
|
};
|
|
9513
9514
|
}
|
|
@@ -5,22 +5,23 @@ argument-hint: "<objective>"
|
|
|
5
5
|
user-invocable: true
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Create
|
|
8
|
+
Create a PromptEmitter that keeps advancing one explicit objective until the goal is achieved, blocked, stopped, or the iteration budget is reached.
|
|
9
9
|
|
|
10
|
-
Use
|
|
10
|
+
Use Codex-style goal-loop rules:
|
|
11
11
|
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
- The model
|
|
16
|
-
- Runtime budget exhaustion is not proof of completion;
|
|
12
|
+
- A goal is a **thread-scoped completion contract**, not a bigger prompt and not global memory.
|
|
13
|
+
- Goals are explicit; do not infer one from ordinary one-shot tasks.
|
|
14
|
+
- The goal contract should name six things: outcome, verification surface, constraints, boundaries, iteration policy, and blocked stop condition.
|
|
15
|
+
- Completion must be evidence-based. The model may stop a goal as complete only after checking concrete evidence.
|
|
16
|
+
- Runtime budget exhaustion is not proof of completion; it is a budget-limited stop/handoff state.
|
|
17
|
+
- Control commands are user-owned (`status`, `stop`, `pause`, `resume`, `clear`, `replace`).
|
|
17
18
|
|
|
18
19
|
## Expected input
|
|
19
20
|
|
|
20
21
|
Interpret the invocation as one of:
|
|
21
22
|
|
|
22
23
|
1. No arguments — show current `goal-*` emitters with `tap_list_emitters`.
|
|
23
|
-
2. A control command — `status`, `stop`, `resume`, `clear`, or `replace`.
|
|
24
|
+
2. A control command — `status`, `stop`, `pause`, `resume`, `clear`, or `replace`.
|
|
24
25
|
3. Otherwise, the full invocation is the goal objective.
|
|
25
26
|
|
|
26
27
|
Example:
|
|
@@ -33,16 +34,49 @@ means:
|
|
|
33
34
|
|
|
34
35
|
- `objective = "migrate the repo to the new API and keep going until tests pass"`
|
|
35
36
|
|
|
36
|
-
If the objective is missing
|
|
37
|
+
If the objective is missing, ask the user for a concrete objective instead of guessing.
|
|
38
|
+
|
|
39
|
+
If the objective is weak but the user's intent is clear, help strengthen it before creating the emitter. A strong goal contract has:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
Outcome: <desired end state>
|
|
43
|
+
Verification surface: <test, benchmark, command output, artifact, or source material that proves completion>
|
|
44
|
+
Constraints: <what must not regress>
|
|
45
|
+
Boundaries: <files, tools, data, repos, or resources allowed>
|
|
46
|
+
Iteration policy: <how to choose the next best action between attempts>
|
|
47
|
+
Blocked stop condition: <what to report if no valid path remains and what would unlock progress>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If one of these fields is not explicitly provided but can be safely inferred from the objective and repository context, infer it and show it in the confirmation. If the verification surface or blocked stop condition cannot be inferred, ask for that missing detail.
|
|
37
51
|
|
|
38
52
|
If another `goal-*` emitter already exists, ask before replacing it unless the user explicitly said `replace`.
|
|
39
53
|
|
|
54
|
+
## Schedule choice
|
|
55
|
+
|
|
56
|
+
Use a **PromptEmitter** in one of two modes:
|
|
57
|
+
|
|
58
|
+
### Default: conservative idle goal
|
|
59
|
+
|
|
60
|
+
Use `every = "idle"` when the user did not ask for autopilot-style busy-session progress.
|
|
61
|
+
|
|
62
|
+
This matches Codex's conservative continuation model: continue only at safe idle boundaries.
|
|
63
|
+
|
|
64
|
+
### Autopilot-compatible timed goal
|
|
65
|
+
|
|
66
|
+
Use `everySchedule = ["2m", "5m", "10m"]` instead of `every = "idle"` when any of these are true:
|
|
67
|
+
|
|
68
|
+
- the user mentions autopilot, busy sessions, continuous work, "keep nudging", or "while Copilot stays busy"
|
|
69
|
+
- the user explicitly says to work autonomously in the current session
|
|
70
|
+
- the current session is in autopilot mode and the goal is expected to advance while other work may be active
|
|
71
|
+
|
|
72
|
+
Timed goal prompts use `session.send()` and can keep the objective visible even when the thread may not become idle often. The runtime preserves the iteration budget when a prompt send is deferred because the session is still busy.
|
|
73
|
+
|
|
40
74
|
## What to create
|
|
41
75
|
|
|
42
|
-
Use `tap_start_emitter
|
|
76
|
+
Use `tap_start_emitter`:
|
|
43
77
|
|
|
44
78
|
- `prompt` — a fully self-contained goal-loop prompt using the template below.
|
|
45
|
-
- `every = "idle"`
|
|
79
|
+
- `every = "idle"` for default goals, OR `everySchedule = ["2m", "5m", "10m"]` for autopilot-compatible goals.
|
|
46
80
|
- `scope = "temporary"`, `managedBy = "modelOwned"`.
|
|
47
81
|
- `subscribe = false` — PromptEmitter output already reaches the session through `session.send()`.
|
|
48
82
|
- `maxRuns` — use the user's requested budget if provided; otherwise default to `50`.
|
|
@@ -58,33 +92,74 @@ Write the prompt so it stands alone because it will run later without the origin
|
|
|
58
92
|
```text
|
|
59
93
|
You are running a tap-goal autonomous goal loop.
|
|
60
94
|
|
|
61
|
-
Goal:
|
|
62
|
-
<
|
|
95
|
+
Goal contract:
|
|
96
|
+
<untrusted_goal_contract>
|
|
97
|
+
Objective:
|
|
63
98
|
<objective>
|
|
64
|
-
|
|
99
|
+
|
|
100
|
+
Outcome:
|
|
101
|
+
<desired end state>
|
|
102
|
+
|
|
103
|
+
Verification surface:
|
|
104
|
+
<test, benchmark, command output, artifact, or source material that proves completion>
|
|
105
|
+
|
|
106
|
+
Constraints:
|
|
107
|
+
<what must not regress>
|
|
108
|
+
|
|
109
|
+
Boundaries:
|
|
110
|
+
<files, tools, data, repos, or resources allowed>
|
|
111
|
+
|
|
112
|
+
Iteration policy:
|
|
113
|
+
<how to choose the next best action between attempts>
|
|
114
|
+
|
|
115
|
+
Blocked stop condition:
|
|
116
|
+
<what to report if no defensible path remains and what would unlock progress>
|
|
117
|
+
</untrusted_goal_contract>
|
|
65
118
|
|
|
66
119
|
Emitter name: <goal-emitter-name>
|
|
120
|
+
EventStream name: <goal-emitter-name>
|
|
121
|
+
Schedule mode: <idle | timed-autopilot>
|
|
67
122
|
Iteration budget: <max-runs>
|
|
68
123
|
|
|
69
124
|
At the start of each iteration:
|
|
70
|
-
1. Call tap_list_emitters and locate the emitter entry
|
|
125
|
+
1. Call tap_list_emitters and locate the emitter entry whose name is exactly '<goal-emitter-name>'.
|
|
71
126
|
2. Read its current runs and maxRuns values.
|
|
72
127
|
3. If the emitter is missing, report that the goal loop is no longer running and stop.
|
|
73
128
|
4. Estimate remaining iterations.
|
|
74
129
|
|
|
75
|
-
|
|
130
|
+
Continuation rules:
|
|
131
|
+
- Treat the goal as a completion contract: work -> check evidence -> continue, complete, or stop blocked.
|
|
76
132
|
- If remaining iterations are low (3 or fewer), switch into wrap-up mode.
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
-
|
|
133
|
+
- If only 1 iteration remains and the goal is not complete, do not start broad new work. Produce a budget-limited handoff instead.
|
|
134
|
+
- Do not treat budget exhaustion or a lifecycle "reached run budget" message as success.
|
|
135
|
+
- If this iteration makes no progress-producing tool calls beyond required status/ledger bookkeeping and does not change evidence, call `tap_post` with `channel='<goal-emitter-name>'` and a no-action handoff, then stop the emitter rather than spinning.
|
|
136
|
+
|
|
137
|
+
Evidence-audit rules:
|
|
138
|
+
- Before marking complete, identify the verification surface from the goal contract.
|
|
139
|
+
- Check the evidence directly: test output, benchmark result, file content, diff, generated artifact, source material, or other concrete proof.
|
|
140
|
+
- Check listed constraints for regressions.
|
|
141
|
+
- If the verification surface cannot be checked, treat the goal as blocked, not complete.
|
|
142
|
+
- Completion requires an explicit evidence audit in the final response and in the EventStream.
|
|
143
|
+
|
|
144
|
+
Research/audit goal rules:
|
|
145
|
+
- For research, reproduction, audit, or investigation goals, maintain a claim ledger.
|
|
146
|
+
- Each ledger item should include: Claim, route attempted, evidence surface, status, and remaining uncertainty.
|
|
147
|
+
- Use statuses such as confirmed, approximate-support, blocked, and uncertain. Do not flatten partial support into success.
|
|
80
148
|
|
|
81
149
|
On this iteration:
|
|
82
150
|
1. Briefly assess current progress toward the goal and the remaining iteration budget.
|
|
83
|
-
2. If the goal is already achieved, call tap_stop_emitter for '<goal-emitter-name>' with scope='temporary', report that the goal is complete, and stop.
|
|
84
|
-
3. If the goal is blocked by missing information, permissions, failing external systems, or an unsafe action, report
|
|
85
|
-
4.
|
|
86
|
-
5.
|
|
87
|
-
6.
|
|
151
|
+
2. If the goal is already achieved, first call `tap_post` with `channel='<goal-emitter-name>'` and a GOAL COMPLETE evidence audit in `message`, then call tap_stop_emitter for '<goal-emitter-name>' with scope='temporary', report that the goal is complete, and stop.
|
|
152
|
+
3. If the goal is blocked by missing information, permissions, failing external systems, or an unsafe action, first call `tap_post` with `channel='<goal-emitter-name>'` and a GOAL BLOCKED report in `message`, then call tap_stop_emitter for '<goal-emitter-name>' with scope='temporary', report the blocker, and stop.
|
|
153
|
+
4. If this is the final iteration and the goal is not complete, do not start substantive new work. Call `tap_post` with `channel='<goal-emitter-name>'` and a BUDGET LIMITED summary in `message`: progress, evidence gathered, remaining work, and recommended next goal or budget. Then leave a concise handoff.
|
|
154
|
+
5. Otherwise, choose the next smallest useful action toward the goal that fits the remaining budget and perform it.
|
|
155
|
+
6. Validate the action using the repository's existing checks when relevant.
|
|
156
|
+
7. End by calling `tap_post` with `channel='<goal-emitter-name>'` and an ITERATION RECORD in `message` containing:
|
|
157
|
+
- iteration and budget used
|
|
158
|
+
- action taken
|
|
159
|
+
- evidence checked and result
|
|
160
|
+
- current status: progressing, complete, blocked, or budget-limited
|
|
161
|
+
- next best action
|
|
162
|
+
8. End the user-visible response with the same concise progress update, what remains, and the next best step if the loop stops before completion.
|
|
88
163
|
|
|
89
164
|
Safety rules:
|
|
90
165
|
- Do not make unrelated changes.
|
|
@@ -95,7 +170,7 @@ Safety rules:
|
|
|
95
170
|
- Stop yourself when done or blocked; do not rely on the user to notice.
|
|
96
171
|
```
|
|
97
172
|
|
|
98
|
-
Substitute the real objective, emitter name, and max iteration count before passing the prompt to `tap_start_emitter`.
|
|
173
|
+
Substitute the real objective, goal-contract fields, emitter name, schedule mode, and max iteration count before passing the prompt to `tap_start_emitter`.
|
|
99
174
|
|
|
100
175
|
## Required behavior
|
|
101
176
|
|
|
@@ -110,26 +185,36 @@ When this skill is invoked:
|
|
|
110
185
|
- if none exist, report that no goal loop is running
|
|
111
186
|
- if multiple exist and the user did not name one, ask them to choose one after showing `/tap-goal status`
|
|
112
187
|
- when you do stop one, call `tap_stop_emitter` with its exact name and confirm that it will not fire again
|
|
113
|
-
4. If the user is asking to pause an existing goal
|
|
114
|
-
|
|
188
|
+
4. If the user is asking to pause an existing goal:
|
|
189
|
+
- Explain that runtime-native pause is not supported because PromptEmitters do not preserve resumable internal state.
|
|
190
|
+
- Offer a simulated pause: call `tap_post` with a PAUSED NOTE containing objective, current status, progress, and resume guidance, then call `tap_stop_emitter`.
|
|
191
|
+
- Only stop the emitter if the user confirms; otherwise leave it running.
|
|
192
|
+
5. If the user is asking to resume a goal:
|
|
193
|
+
- If they provide an objective, create a new `/tap-goal` loop from it.
|
|
194
|
+
- If they name a prior goal stream, inspect its history with `tap_stream_history` using `channel='<goal-stream-name>'`, recover the latest PAUSED NOTE or handoff if available, and create a new loop from that objective.
|
|
195
|
+
- If the objective is not clear, ask for it.
|
|
115
196
|
6. Before creating a new goal, check for existing `goal-*` emitters. If one exists and the user did not explicitly ask to replace it, ask for confirmation before starting another goal loop.
|
|
116
|
-
7.
|
|
117
|
-
8.
|
|
197
|
+
7. Choose idle vs timed-autopilot schedule using the schedule rules above.
|
|
198
|
+
8. Create the PromptEmitter using the template above.
|
|
118
199
|
9. Confirm to the user:
|
|
119
200
|
- Goal emitter name
|
|
120
201
|
- EventStream name
|
|
121
202
|
- Objective
|
|
203
|
+
- Verification surface
|
|
204
|
+
- Constraints
|
|
205
|
+
- Schedule mode (`idle` or `timed-autopilot`)
|
|
122
206
|
- Max iteration count
|
|
123
|
-
- That it will
|
|
207
|
+
- That it will stop itself when complete, blocked, or budget-limited
|
|
124
208
|
10. Stop there. Do not immediately perform the first goal iteration unless the user explicitly asks you to start working now.
|
|
125
209
|
|
|
126
210
|
## Iteration budget
|
|
127
211
|
|
|
128
|
-
|
|
212
|
+
Goal loops must always have `maxRuns`.
|
|
129
213
|
|
|
130
214
|
- If the user gives a budget, use it.
|
|
131
215
|
- Otherwise, default to `50`.
|
|
132
216
|
- If the objective is large, tell the user they can invoke `/tap-goal` again with a higher budget.
|
|
217
|
+
- Budget exhaustion is a handoff state, not success.
|
|
133
218
|
|
|
134
219
|
## Persistence
|
|
135
220
|
|
package/dist/version.json
CHANGED