clideck 1.31.16 → 1.31.18
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 +4 -4
- package/activity.js +11 -66
- package/agent-presets.json +19 -1
- package/ansi-utils.js +7 -0
- package/bin/claude-hook.js +3 -0
- package/claude-session.js +17 -0
- package/config.js +3 -5
- package/handlers.js +92 -14
- package/http-util.js +20 -0
- package/package.json +1 -1
- package/pi-bridge.js +51 -0
- package/pi-extension/clideck-bridge.ts +34 -0
- package/preset-utils.js +13 -0
- package/public/img/pi.svg +13 -0
- package/public/index.html +4 -1
- package/public/js/app.js +36 -11
- package/public/js/hotkeys.js +11 -0
- package/public/js/settings.js +1 -0
- package/public/js/terminals.js +2 -1
- package/public/tailwind.css +1 -1
- package/server.js +28 -18
- package/session-agents.js +1 -18
- package/session-ask.js +1 -19
- package/sessions.js +26 -21
- package/telemetry-receiver.js +8 -27
- package/transcript.js +3 -2
- package/skills/autonomous-session/SKILL.md +0 -211
- package/skills/research-experiment/SKILL.md +0 -411
- package/skills/research-experiment/SKILL.md.bak +0 -224
- package/skills/research-experiment/scripts/init-research-layout.mjs +0 -184
package/sessions.js
CHANGED
|
@@ -7,12 +7,14 @@ const activity = require('./activity');
|
|
|
7
7
|
const transcript = require('./transcript');
|
|
8
8
|
const telemetry = require('./telemetry-receiver');
|
|
9
9
|
const opencodeBridge = require('./opencode-bridge');
|
|
10
|
+
const piBridge = require('./pi-bridge');
|
|
10
11
|
const plugins = require('./plugin-loader');
|
|
12
|
+
const { presetForCommand } = require('./preset-utils');
|
|
13
|
+
const { stripAnsi } = require('./ansi-utils');
|
|
11
14
|
|
|
12
15
|
const THEMES = require('./themes');
|
|
13
16
|
const MAX_BUFFER = 2 * 1024 * 1024;
|
|
14
17
|
const { PORT, localUrl } = require('./runtime');
|
|
15
|
-
const ANSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\].*?(?:\x07|\x1b\\)|\x1b./g;
|
|
16
18
|
const PRESETS = JSON.parse(require('fs').readFileSync(join(__dirname, 'agent-presets.json'), 'utf8'));
|
|
17
19
|
for (const p of PRESETS) if (p.presetId === 'shell') p.command = defaultShell;
|
|
18
20
|
const { DATA_DIR } = require('./paths');
|
|
@@ -37,6 +39,9 @@ function broadcast(msg) {
|
|
|
37
39
|
const raw = JSON.stringify(msg);
|
|
38
40
|
for (const c of clients) if (c.readyState === 1) c.send(raw);
|
|
39
41
|
if (msg.type === 'session.status') {
|
|
42
|
+
// Status broadcasts currently also apply the local state transition. This is
|
|
43
|
+
// intentional for now but couples transport with session state; if this area
|
|
44
|
+
// changes, split it into a dedicated setSessionStatus() transition first.
|
|
40
45
|
const s = sessions.get(msg.id);
|
|
41
46
|
if (s) {
|
|
42
47
|
s.working = !!msg.working;
|
|
@@ -59,14 +64,7 @@ function broadcast(msg) {
|
|
|
59
64
|
|
|
60
65
|
// --- Spawn a PTY and wire up a session ---
|
|
61
66
|
|
|
62
|
-
function presetForCommand(cmd)
|
|
63
|
-
if (cmd?.presetId) {
|
|
64
|
-
const preset = PRESETS.find(p => p.presetId === cmd.presetId);
|
|
65
|
-
if (preset) return preset;
|
|
66
|
-
}
|
|
67
|
-
const bin = binName(cmd?.command);
|
|
68
|
-
return PRESETS.find(p => binName(p.command) === bin);
|
|
69
|
-
}
|
|
67
|
+
function matchPreset(cmd) { return presetForCommand(cmd, PRESETS); }
|
|
70
68
|
|
|
71
69
|
function commandEnv(cmd) {
|
|
72
70
|
const env = {};
|
|
@@ -78,7 +76,7 @@ function commandEnv(cmd) {
|
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
function buildTelemetryEnv(id, cmd) {
|
|
81
|
-
const preset =
|
|
79
|
+
const preset = matchPreset(cmd);
|
|
82
80
|
const telemetryEnabled = cmd.telemetryEnabled ?? (preset?.presetId === 'claude-code');
|
|
83
81
|
const env = { CLIDECK_SESSION_ID: id, CLIDECK_PORT: String(PORT), CLIDECK_URL: localUrl() };
|
|
84
82
|
if (!preset?.telemetryEnv || !telemetryEnabled) return env;
|
|
@@ -114,10 +112,10 @@ function spawnSession(id, cmd, parts, cwd, name, themeId, commandId, savedToken,
|
|
|
114
112
|
}
|
|
115
113
|
|
|
116
114
|
const sessionIdRe = cmd.sessionIdPattern ? new RegExp(cmd.sessionIdPattern, 'i') : null;
|
|
117
|
-
const preset =
|
|
115
|
+
const preset = matchPreset(cmd);
|
|
118
116
|
const session = { name, themeId, commandId, cwd, pty: term, chunks: [], chunksSize: 0, sessionToken: savedToken || null, projectId: projectId || null, presetId: preset?.presetId || 'shell', working: undefined };
|
|
119
117
|
sessions.set(id, session);
|
|
120
|
-
transcript.setFinalizeOnIdle(id, ['claude-code', 'codex', 'gemini-cli', 'opencode', 'clideck-agent'].includes(session.presetId) ? session.presetId : null);
|
|
118
|
+
transcript.setFinalizeOnIdle(id, ['claude-code', 'codex', 'gemini-cli', 'opencode', 'pi', 'clideck-agent'].includes(session.presetId) ? session.presetId : null);
|
|
121
119
|
|
|
122
120
|
// Always watch telemetry-backed agents so OTLP fallback matching can attach
|
|
123
121
|
// early events to this session even when the agent omits clideck.session_id.
|
|
@@ -134,7 +132,7 @@ function spawnSession(id, cmd, parts, cwd, name, themeId, commandId, savedToken,
|
|
|
134
132
|
// Capture session ID from output
|
|
135
133
|
if (sessionIdRe && !session.sessionToken) {
|
|
136
134
|
const joined = session.chunks.join('');
|
|
137
|
-
const match = joined.match(sessionIdRe) || joined
|
|
135
|
+
const match = joined.match(sessionIdRe) || stripAnsi(joined).match(sessionIdRe);
|
|
138
136
|
if (match) {
|
|
139
137
|
session.sessionToken = match[1];
|
|
140
138
|
console.log(`Session ${id.slice(0, 8)}: captured token via output regex: ${match[1].slice(0, 12)}…`);
|
|
@@ -153,6 +151,7 @@ function spawnSession(id, cmd, parts, cwd, name, themeId, commandId, savedToken,
|
|
|
153
151
|
activity.clear(id);
|
|
154
152
|
telemetry.clear(id);
|
|
155
153
|
opencodeBridge.clear(id);
|
|
154
|
+
piBridge.clear(id);
|
|
156
155
|
plugins.clearStatus(id);
|
|
157
156
|
// If resumable and token captured, move to resumable list (keep transcript for search)
|
|
158
157
|
if (!s.ephemeral && cmd.canResume && cmd.resumeCommand && s.sessionToken) {
|
|
@@ -196,12 +195,12 @@ function create(msg, ws, cfg) {
|
|
|
196
195
|
return;
|
|
197
196
|
}
|
|
198
197
|
|
|
199
|
-
const createdPresetId =
|
|
198
|
+
const createdPresetId = matchPreset(cmd)?.presetId || 'shell';
|
|
200
199
|
const installId = msg.installId || undefined;
|
|
201
200
|
broadcast({ type: 'created', id, name, themeId, commandId: cmd.id, presetId: createdPresetId, projectId, installId });
|
|
202
201
|
|
|
203
202
|
// Immediate setup notification if config not detected
|
|
204
|
-
const preset =
|
|
203
|
+
const preset = matchPreset(cmd);
|
|
205
204
|
if (preset && (preset.telemetrySetup || preset.bridge) && !(cmd.telemetryEnabled && cmd.telemetryStatus?.ok)) {
|
|
206
205
|
broadcast({ type: 'session.needsSetup', id });
|
|
207
206
|
}
|
|
@@ -228,7 +227,7 @@ function createProgrammatic(opts, cfg) {
|
|
|
228
227
|
const s = sessions.get(id);
|
|
229
228
|
if (s && opts.ephemeral) s.ephemeral = true;
|
|
230
229
|
|
|
231
|
-
const presetId =
|
|
230
|
+
const presetId = matchPreset(cmd)?.presetId || 'shell';
|
|
232
231
|
broadcast({ type: 'created', id, name, themeId, commandId: cmd.id, presetId, projectId });
|
|
233
232
|
return { id };
|
|
234
233
|
}
|
|
@@ -278,7 +277,7 @@ function resume(msg, ws, cfg) {
|
|
|
278
277
|
resumable = resumable.filter(s => s.id !== id);
|
|
279
278
|
broadcast({ type: 'sessions.resumable', list: getResumable(cfg) });
|
|
280
279
|
|
|
281
|
-
const resumePresetId =
|
|
280
|
+
const resumePresetId = matchPreset(cmd)?.presetId || saved.presetId || 'shell';
|
|
282
281
|
broadcast({ type: 'created', id, name: saved.name, themeId: saved.themeId || saved.profileId || 'default', commandId: saved.commandId, presetId: resumePresetId, projectId: saved.projectId || null, muted: !!saved.muted, resumed: true, lastPreview: saved.lastPreview || '' });
|
|
283
282
|
}
|
|
284
283
|
|
|
@@ -305,9 +304,13 @@ function input(msg) {
|
|
|
305
304
|
// manual flows.
|
|
306
305
|
if (!plugins.shouldAutoApproveMenu(msg.id)) s._resolvedMenuKey = s._menuKey;
|
|
307
306
|
if (s._menuActiveVersion) s._menuConsumedVersion = s._menuActiveVersion;
|
|
307
|
+
const menuStartsWork = s._menuStartsWork !== false;
|
|
308
308
|
s._menuKey = '';
|
|
309
|
+
s._menuStartsWork = undefined;
|
|
309
310
|
broadcast({ type: 'session.menu', id: msg.id, choices: [] });
|
|
310
|
-
|
|
311
|
+
if (menuStartsWork) {
|
|
312
|
+
broadcast({ type: 'session.status', id: msg.id, working: true, source: 'menu-input' });
|
|
313
|
+
}
|
|
311
314
|
return;
|
|
312
315
|
}
|
|
313
316
|
writeSessionInput(msg.id, data);
|
|
@@ -337,7 +340,7 @@ function setMute(id, muted) {
|
|
|
337
340
|
|
|
338
341
|
function close(msg, cfg) {
|
|
339
342
|
const s = sessions.get(msg.id);
|
|
340
|
-
if (s) { s.pty.kill(); telemetry.clear(msg.id); transcript.clear(msg.id); plugins.clearStatus(msg.id); sessions.delete(msg.id); broadcast({ type: 'closed', id: msg.id }); }
|
|
343
|
+
if (s) { s.pty.kill(); telemetry.clear(msg.id); opencodeBridge.clear(msg.id); piBridge.clear(msg.id); transcript.clear(msg.id); plugins.clearStatus(msg.id); sessions.delete(msg.id); broadcast({ type: 'closed', id: msg.id }); }
|
|
341
344
|
// Also remove from resumable list if present
|
|
342
345
|
const before = resumable.length;
|
|
343
346
|
resumable = resumable.filter(r => r.id !== msg.id);
|
|
@@ -370,6 +373,7 @@ function restart(msg, ws, cfg) {
|
|
|
370
373
|
activity.clear(id);
|
|
371
374
|
telemetry.clear(id);
|
|
372
375
|
opencodeBridge.clear(id);
|
|
376
|
+
piBridge.clear(id);
|
|
373
377
|
transcript.clear(id);
|
|
374
378
|
|
|
375
379
|
s.pty.kill();
|
|
@@ -395,6 +399,7 @@ function restart(msg, ws, cfg) {
|
|
|
395
399
|
function list() {
|
|
396
400
|
return [...sessions].map(([id, s]) => ({
|
|
397
401
|
id, name: s.name, themeId: s.themeId, commandId: s.commandId, presetId: s.presetId || 'shell', projectId: s.projectId, muted: !!s.muted,
|
|
402
|
+
working: !!s.working,
|
|
398
403
|
// Last preview text for sidebar display on reconnect
|
|
399
404
|
lastPreview: s.lastPreview || '', lastActivityAt: s.lastActivityAt || null,
|
|
400
405
|
menu: s._menuKey ? JSON.parse(s._menuKey) : undefined,
|
|
@@ -422,7 +427,7 @@ function getResumable(cfg) {
|
|
|
422
427
|
if (s.presetId) return s;
|
|
423
428
|
const cmd = (cfg.commands || []).find(c => c.id === s.commandId);
|
|
424
429
|
if (!cmd) return { ...s, presetId: 'shell' };
|
|
425
|
-
const preset =
|
|
430
|
+
const preset = matchPreset(cmd);
|
|
426
431
|
return { ...s, presetId: preset?.presetId || 'shell' };
|
|
427
432
|
});
|
|
428
433
|
}
|
|
@@ -434,7 +439,7 @@ function sendBuffers(ws) {
|
|
|
434
439
|
ws.send(JSON.stringify({ type: 'output', id, data, replay: true }));
|
|
435
440
|
continue;
|
|
436
441
|
}
|
|
437
|
-
if (['claude-code', 'codex', 'gemini-cli', 'opencode', 'clideck-agent'].includes(s.presetId) && !s.working) {
|
|
442
|
+
if (['claude-code', 'codex', 'gemini-cli', 'opencode', 'pi', 'clideck-agent'].includes(s.presetId) && !s.working) {
|
|
438
443
|
const text = transcript.getReplayText(id, s.presetId);
|
|
439
444
|
if (text) {
|
|
440
445
|
ws.send(JSON.stringify({ type: 'session.history', id, text, replay: true }));
|
package/telemetry-receiver.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// CLI agents export telemetry events here; we capture agent session IDs
|
|
3
3
|
// (for resume) and detect whether telemetry is configured (setup prompts).
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { updateClaudeSessionToken } = require('./claude-session');
|
|
6
|
+
|
|
6
7
|
const activity = new Map(); // sessionId → has received events
|
|
7
8
|
const lastEvent = new Map(); // sessionId → last OTEL event name (+ kind)
|
|
8
9
|
const pendingSetup = new Map(); // sessionId → timer (waiting for first event)
|
|
@@ -10,21 +11,14 @@ const codexMenuPoll = new Map(); // sessionId → interval (polling for menu aft
|
|
|
10
11
|
const codexPendingStop = new Map(); // sessionId → ts (notify hook arrived; wait for next response.completed)
|
|
11
12
|
const codexOutputDone = new Map(); // sessionId → ts (fallback if notify never fires)
|
|
12
13
|
const codexPendingIdle = new Map(); // sessionId → timer (tiny settle before committing idle)
|
|
14
|
+
// Codex does not currently expose one reliable "fully idle" signal across streamed
|
|
15
|
+
// output, tool calls, and approval menus. This state machine is the best available
|
|
16
|
+
// approach for now; do not add more timing patches without fixture tests from real
|
|
17
|
+
// Codex event sequences.
|
|
13
18
|
const codexToolPhasePending = new Set(); // sessionId set once Codex has announced a tool-call phase, cleared when the phase resolves
|
|
14
19
|
const codexPendingTools = new Map(); // sessionId → Set(callId) for approved Codex tool calls still awaiting a result
|
|
15
20
|
let broadcastFn = null;
|
|
16
21
|
let sessionsFn = null;
|
|
17
|
-
const CLAUDE_SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
18
|
-
|
|
19
|
-
function updateClaudeSessionToken(sess, token, clideckId) {
|
|
20
|
-
const next = String(token || '').trim();
|
|
21
|
-
if (!sess || sess.presetId !== 'claude-code' || !CLAUDE_SESSION_ID_RE.test(next)) return false;
|
|
22
|
-
if (sess.sessionToken === next) return false;
|
|
23
|
-
const prev = sess.sessionToken;
|
|
24
|
-
sess.sessionToken = next;
|
|
25
|
-
console.log(`Telemetry: updated Claude session ID for ${clideckId.slice(0, 8)}: ${prev ? prev.slice(0, 12) + '... -> ' : ''}${next.slice(0, 12)}...`);
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
22
|
|
|
29
23
|
function getPendingToolSet(id) {
|
|
30
24
|
let set = codexPendingTools.get(id);
|
|
@@ -218,7 +212,7 @@ function handleLogs(req, res) {
|
|
|
218
212
|
: (attrs['session.id'] || attrs['conversation.id']);
|
|
219
213
|
if (agentSessionId && sess) {
|
|
220
214
|
if (serviceName === 'claude-code') {
|
|
221
|
-
updateClaudeSessionToken(sess, agentSessionId, resolvedId);
|
|
215
|
+
updateClaudeSessionToken(sess, agentSessionId, resolvedId, { label: 'Telemetry' });
|
|
222
216
|
continue;
|
|
223
217
|
}
|
|
224
218
|
// Prefer interactive session ID (Gemini sends non-interactive init events first)
|
|
@@ -289,14 +283,6 @@ function markCodexStart(id, source = 'hook') {
|
|
|
289
283
|
broadcastFn?.({ type: 'session.status', id, working: true, source });
|
|
290
284
|
}
|
|
291
285
|
|
|
292
|
-
function markCodexIdle(id, source = 'hook') {
|
|
293
|
-
codexPendingStop.delete(id);
|
|
294
|
-
codexOutputDone.delete(id);
|
|
295
|
-
codexToolPhasePending.delete(id);
|
|
296
|
-
clearPendingTools(id);
|
|
297
|
-
scheduleCodexIdle(id, source);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
286
|
function scheduleCodexIdle(id, source) {
|
|
301
287
|
cancelCodexPendingIdle(id);
|
|
302
288
|
const timer = setTimeout(() => {
|
|
@@ -326,9 +312,4 @@ function clear(id) {
|
|
|
326
312
|
|
|
327
313
|
function getLastEvent(id) { return lastEvent.get(id) || ''; }
|
|
328
314
|
|
|
329
|
-
|
|
330
|
-
function hasEvents(id) {
|
|
331
|
-
return activity.has(id);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
module.exports = { init, handleLogs, clear, hasEvents, getLastEvent, cancelCodexMenuPoll, watchSession, armCodexStop, markCodexStart, markCodexIdle };
|
|
315
|
+
module.exports = { init, handleLogs, clear, getLastEvent, cancelCodexMenuPoll, watchSession, armCodexStop, markCodexStart };
|
package/transcript.js
CHANGED
|
@@ -4,9 +4,9 @@ const { DATA_DIR } = require('./paths');
|
|
|
4
4
|
const builder = require('./transcript-normalizer');
|
|
5
5
|
const parser = require('./transcript-parser');
|
|
6
6
|
const candidate = require('./transcript-candidate');
|
|
7
|
+
const { stripAnsi } = require('./ansi-utils');
|
|
7
8
|
|
|
8
9
|
const DIR = join(DATA_DIR, 'transcripts');
|
|
9
|
-
const ANSI_RE = /\x1b[\[\]()#;?]*[0-9;]*[a-zA-Z@`~]|\x1b\].*?(?:\x07|\x1b\\)|\x1b.|\r|\x07/g;
|
|
10
10
|
const MAX_CACHE = 50 * 1024;
|
|
11
11
|
const LEGACY_SUFFIXES = ['-parsed.jsonl', '.screen'];
|
|
12
12
|
|
|
@@ -153,7 +153,7 @@ function trackOutput(id, data) {
|
|
|
153
153
|
function flush(id) {
|
|
154
154
|
const buf = outputBuf[id];
|
|
155
155
|
if (!buf?.text) return;
|
|
156
|
-
const clean = buf.text
|
|
156
|
+
const clean = stripAnsi(buf.text).replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '');
|
|
157
157
|
const lines = clean.split('\n').map(l => l.trim()).filter(l => l.length > 2);
|
|
158
158
|
buf.text = '';
|
|
159
159
|
if (lines.length) store(id, 'agent', lines.join('\n'));
|
|
@@ -238,6 +238,7 @@ function getReplayText(id, presetId) {
|
|
|
238
238
|
codex: { user: '›', agent: '•' },
|
|
239
239
|
'gemini-cli': { user: '>', agent: '✦' },
|
|
240
240
|
opencode: { user: '›', agent: '•' },
|
|
241
|
+
pi: { user: '›', agent: '•' },
|
|
241
242
|
}[presetId] || { user: '›', agent: '•' };
|
|
242
243
|
return entries.map(e => `${e.role === 'user' ? marks.user : marks.agent} ${e.text}`).join('\n\n');
|
|
243
244
|
}
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: autonomous-session
|
|
3
|
-
description: Run one agent session autonomously until a clearly defined goal is achieved or truly blocked. Use when the user wants the agent to keep working without repeated check-ins, across coding, research, writing, analysis, marketing, planning, or other general session work.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Autonomous Session
|
|
7
|
-
|
|
8
|
-
Use this skill when the user wants one agent session to keep working toward a goal without stopping for routine confirmation.
|
|
9
|
-
|
|
10
|
-
This skill is general-purpose. It is not limited to coding. It applies to research, writing, planning, analysis, marketing, documentation, and other session-based work.
|
|
11
|
-
|
|
12
|
-
## Core Contract
|
|
13
|
-
|
|
14
|
-
You are not waiting for permission after every step.
|
|
15
|
-
|
|
16
|
-
- Understand the goal precisely.
|
|
17
|
-
- Keep working until the goal is achieved or truly blocked.
|
|
18
|
-
- Do not stop just to ask whether you should continue.
|
|
19
|
-
- Do not produce filler progress updates instead of real work.
|
|
20
|
-
- Do not redefine the goal casually once work has started.
|
|
21
|
-
|
|
22
|
-
## First Check: Can This Session Actually Run Autonomously?
|
|
23
|
-
|
|
24
|
-
Before doing substantial work, verify that the session can proceed without routine approval interruptions.
|
|
25
|
-
|
|
26
|
-
If the environment clearly requires recurring user approval for normal work, stop immediately and tell the user, in plain language, that autonomous mode cannot work until approvals are removed or auto-approval is enabled.
|
|
27
|
-
|
|
28
|
-
Do not try to fake autonomy in a session that will keep pausing for user approval.
|
|
29
|
-
|
|
30
|
-
## Goal Setup
|
|
31
|
-
|
|
32
|
-
Before starting the main work, convert the user request into a concrete internal brief.
|
|
33
|
-
|
|
34
|
-
Your internal brief must include:
|
|
35
|
-
|
|
36
|
-
- Goal: what outcome must exist at the end.
|
|
37
|
-
- Constraints: what must not happen.
|
|
38
|
-
- Definition of done: how you will recognize completion.
|
|
39
|
-
- Open questions: only the questions that would materially change the work.
|
|
40
|
-
|
|
41
|
-
If the goal is already clear enough, do not ask questions. Start working.
|
|
42
|
-
|
|
43
|
-
If the goal is not clear enough to work effectively, ask a small batch of targeted clarifying questions first. Ask only what is necessary to remove ambiguity. Do not interrogate the user unnecessarily.
|
|
44
|
-
|
|
45
|
-
Examples of when to ask questions first:
|
|
46
|
-
|
|
47
|
-
- The user wants research but has not said what decision the research is meant to support.
|
|
48
|
-
- The user wants writing but has not said audience, tone, or deliverable type.
|
|
49
|
-
- The user wants implementation but has not said what behavior should change.
|
|
50
|
-
- The user wants “improve this” but there is no clear success condition.
|
|
51
|
-
|
|
52
|
-
Examples of when not to ask questions first:
|
|
53
|
-
|
|
54
|
-
- The user already gave a concrete task, constraints, and acceptance bar.
|
|
55
|
-
- You can infer a safe, reasonable working interpretation without risking the wrong output.
|
|
56
|
-
|
|
57
|
-
## Goal Memory
|
|
58
|
-
|
|
59
|
-
If the task involves a real project or working directory, create and maintain a short session memory file early in the process.
|
|
60
|
-
|
|
61
|
-
Preferred filename:
|
|
62
|
-
|
|
63
|
-
```text
|
|
64
|
-
autonomous-session.md
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Keep it concise and practical. It should contain:
|
|
68
|
-
|
|
69
|
-
- Goal
|
|
70
|
-
- Constraints
|
|
71
|
-
- Definition of done
|
|
72
|
-
- Key decisions
|
|
73
|
-
- What has been completed
|
|
74
|
-
- Remaining gaps
|
|
75
|
-
|
|
76
|
-
If a different filename is more natural in the project, use that instead.
|
|
77
|
-
|
|
78
|
-
If there is no meaningful project directory or file-based workflow, maintain the same structure mentally and in your session responses instead of forcing a file.
|
|
79
|
-
|
|
80
|
-
Update this memory whenever the goal changes materially or when major decisions are made. Keep it short. It is a working anchor, not a diary.
|
|
81
|
-
|
|
82
|
-
## Operating Rules
|
|
83
|
-
|
|
84
|
-
### 1. Work Forward
|
|
85
|
-
|
|
86
|
-
After the goal is clear, move directly into execution.
|
|
87
|
-
|
|
88
|
-
- Prefer real progress over commentary.
|
|
89
|
-
- Prefer concrete artifacts over abstract planning.
|
|
90
|
-
- Prefer finishing a meaningful chunk before reporting back.
|
|
91
|
-
|
|
92
|
-
### 2. Do Not Stop Early
|
|
93
|
-
|
|
94
|
-
Do not ask:
|
|
95
|
-
|
|
96
|
-
- “Should I continue?”
|
|
97
|
-
- “Do you want me to keep going?”
|
|
98
|
-
- “Is this enough for now?”
|
|
99
|
-
|
|
100
|
-
The default is to continue until done or blocked.
|
|
101
|
-
|
|
102
|
-
### 3. Use Judgment, Not Blind Persistence
|
|
103
|
-
|
|
104
|
-
Autonomy does not mean mindless looping.
|
|
105
|
-
|
|
106
|
-
If an approach is not working:
|
|
107
|
-
|
|
108
|
-
- reassess,
|
|
109
|
-
- read the available context again,
|
|
110
|
-
- change tactics,
|
|
111
|
-
- keep moving.
|
|
112
|
-
|
|
113
|
-
Do not repeat the same failing pattern without learning from it.
|
|
114
|
-
|
|
115
|
-
### 4. Respect the Actual Task
|
|
116
|
-
|
|
117
|
-
Do not turn every task into implementation work.
|
|
118
|
-
|
|
119
|
-
- For research tasks, gather, compare, synthesize, and conclude.
|
|
120
|
-
- For writing tasks, produce and refine the requested deliverable.
|
|
121
|
-
- For planning tasks, produce the plan and then, if appropriate, execute it.
|
|
122
|
-
- For coding tasks, inspect, implement, verify, and refine.
|
|
123
|
-
|
|
124
|
-
Stay aligned with the actual requested outcome.
|
|
125
|
-
|
|
126
|
-
### 5. Completion Must Be Real
|
|
127
|
-
|
|
128
|
-
Only stop when one of these is true:
|
|
129
|
-
|
|
130
|
-
- The goal is achieved.
|
|
131
|
-
- The remaining blocker genuinely requires user input, approval, credentials, or a missing external dependency.
|
|
132
|
-
- The request is fundamentally ambiguous and cannot be resolved safely without clarification.
|
|
133
|
-
|
|
134
|
-
When stopping, say which of those is true.
|
|
135
|
-
|
|
136
|
-
## Blockers
|
|
137
|
-
|
|
138
|
-
A blocker is real only if you cannot reasonably move forward without the user.
|
|
139
|
-
|
|
140
|
-
Examples of real blockers:
|
|
141
|
-
|
|
142
|
-
- Missing credentials, API keys, access, or required permissions.
|
|
143
|
-
- A strategic choice the user must make because it changes the deliverable substantially.
|
|
144
|
-
- Multiple valid directions remain and choosing one would be risky or expensive without user preference.
|
|
145
|
-
- The environment prevents autonomous execution through approval prompts or missing capabilities.
|
|
146
|
-
|
|
147
|
-
Examples of non-blockers:
|
|
148
|
-
|
|
149
|
-
- You are unsure which tactic is best.
|
|
150
|
-
- The first attempt failed.
|
|
151
|
-
- More reading is needed.
|
|
152
|
-
- The work is tedious.
|
|
153
|
-
- You can make a reasonable assumption and continue.
|
|
154
|
-
|
|
155
|
-
## Interruptions And Mid-Task User Messages
|
|
156
|
-
|
|
157
|
-
If the user sends a new message during the work:
|
|
158
|
-
|
|
159
|
-
- incorporate it,
|
|
160
|
-
- update the goal brief if needed,
|
|
161
|
-
- continue from the new state.
|
|
162
|
-
|
|
163
|
-
Do not stubbornly follow an outdated plan when the user has clarified or redirected the work.
|
|
164
|
-
|
|
165
|
-
If the new message changes the goal materially, update the session memory file.
|
|
166
|
-
|
|
167
|
-
## Reporting Style
|
|
168
|
-
|
|
169
|
-
Use sparse, meaningful updates.
|
|
170
|
-
|
|
171
|
-
Good updates:
|
|
172
|
-
|
|
173
|
-
- major completed milestone,
|
|
174
|
-
- important decision,
|
|
175
|
-
- real blocker,
|
|
176
|
-
- final completion summary.
|
|
177
|
-
|
|
178
|
-
Bad updates:
|
|
179
|
-
|
|
180
|
-
- empty status chatter,
|
|
181
|
-
- repeated reassurance,
|
|
182
|
-
- asking for permission to continue.
|
|
183
|
-
|
|
184
|
-
## Completion Message
|
|
185
|
-
|
|
186
|
-
When the goal is done, report:
|
|
187
|
-
|
|
188
|
-
- what was accomplished,
|
|
189
|
-
- any important decisions or tradeoffs,
|
|
190
|
-
- any residual risks or follow-up items.
|
|
191
|
-
|
|
192
|
-
Keep it concise and outcome-focused.
|
|
193
|
-
|
|
194
|
-
## Behavior Summary
|
|
195
|
-
|
|
196
|
-
If this skill is active, your default behavior is:
|
|
197
|
-
|
|
198
|
-
1. Check whether autonomous execution is actually possible.
|
|
199
|
-
2. Clarify the goal only if necessary.
|
|
200
|
-
3. Create a short working brief or memory file when appropriate.
|
|
201
|
-
4. Work continuously toward the goal.
|
|
202
|
-
5. Adapt when an approach fails.
|
|
203
|
-
6. Stop only when done or truly blocked.
|
|
204
|
-
|
|
205
|
-
## Hard Rules
|
|
206
|
-
|
|
207
|
-
- Do not ask “should I continue?”
|
|
208
|
-
- Do not stop because of ordinary uncertainty.
|
|
209
|
-
- Do not continue blindly when the goal is unclear.
|
|
210
|
-
- Do not pretend a blocker exists when you can still make progress.
|
|
211
|
-
- Do not treat a status update as completion.
|