sisyphi 1.1.8 → 1.1.9
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/dist/cli.js +854 -160
- package/dist/cli.js.map +1 -1
- package/dist/templates/nvim-tutorial.txt +68 -0
- package/dist/templates/tutorial-demo/CLAUDE.md +14 -0
- package/dist/templates/tutorial-demo/package.json +10 -0
- package/dist/templates/tutorial-demo/server.js +76 -0
- package/dist/templates/tutorial-demo/test.js +48 -0
- package/dist/templates/tutorial-demo/todo.js +35 -0
- package/package.json +1 -1
- package/templates/nvim-tutorial.txt +68 -0
- package/templates/tutorial-demo/CLAUDE.md +14 -0
- package/templates/tutorial-demo/package.json +10 -0
- package/templates/tutorial-demo/server.js +76 -0
- package/templates/tutorial-demo/test.js +48 -0
- package/templates/tutorial-demo/todo.js +35 -0
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
shellQuote
|
|
11
11
|
} from "./chunk-6G226ZK7.js";
|
|
12
12
|
import {
|
|
13
|
+
cycleLogPath,
|
|
13
14
|
daemonLogPath,
|
|
14
15
|
daemonPidPath,
|
|
15
16
|
daemonUpdatingPath,
|
|
@@ -20,9 +21,9 @@ import {
|
|
|
20
21
|
|
|
21
22
|
// src/cli/index.ts
|
|
22
23
|
import { Command } from "commander";
|
|
23
|
-
import { existsSync as
|
|
24
|
-
import { dirname as
|
|
25
|
-
import { fileURLToPath as
|
|
24
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync5 } from "fs";
|
|
25
|
+
import { dirname as dirname4, join as join8 } from "path";
|
|
26
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
26
27
|
|
|
27
28
|
// src/cli/commands/start.ts
|
|
28
29
|
import { execSync as execSync5 } from "child_process";
|
|
@@ -91,8 +92,9 @@ while IFS= read -r name; do
|
|
|
91
92
|
scwd=$(tmux show-option -t "$name" -v @sisyphus_cwd 2>/dev/null)
|
|
92
93
|
if [ "$scwd" = "$cwd" ]; then
|
|
93
94
|
tmux switch-client -t "$name"
|
|
94
|
-
# Focus the dashboard window
|
|
95
|
-
tmux
|
|
95
|
+
# Focus the dashboard window by stored ID (not name)
|
|
96
|
+
dwid=$(tmux show-option -t "$name" -v @sisyphus_dashboard 2>/dev/null)
|
|
97
|
+
[ -n "$dwid" ] && tmux select-window -t "$dwid" 2>/dev/null
|
|
96
98
|
exit 0
|
|
97
99
|
fi
|
|
98
100
|
done < <(tmux list-sessions -F '#{session_name}')
|
|
@@ -112,7 +114,8 @@ if [ "$pane_count" -le 1 ]; then
|
|
|
112
114
|
scwd=$(tmux show-option -t "$name" -v @sisyphus_cwd 2>/dev/null)
|
|
113
115
|
if [ "$scwd" = "$cwd" ]; then
|
|
114
116
|
tmux switch-client -t "$name"
|
|
115
|
-
tmux
|
|
117
|
+
dwid=$(tmux show-option -t "$name" -v @sisyphus_dashboard 2>/dev/null)
|
|
118
|
+
[ -n "$dwid" ] && tmux select-window -t "$dwid" 2>/dev/null
|
|
116
119
|
tmux kill-session -t "$session"
|
|
117
120
|
exit 0
|
|
118
121
|
fi
|
|
@@ -486,18 +489,22 @@ function getTmuxSession() {
|
|
|
486
489
|
// src/cli/commands/dashboard.ts
|
|
487
490
|
import { join as join3 } from "path";
|
|
488
491
|
import { execSync as execSync4 } from "child_process";
|
|
489
|
-
function
|
|
492
|
+
function openDashboardWindow(tmuxSession, cwd) {
|
|
490
493
|
try {
|
|
491
|
-
const
|
|
492
|
-
`tmux
|
|
493
|
-
{ encoding: "utf-8" }
|
|
494
|
-
);
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
494
|
+
const storedId = execSync4(
|
|
495
|
+
`tmux show-option -t ${shellQuote(tmuxSession)} -v @sisyphus_dashboard`,
|
|
496
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
497
|
+
).trim();
|
|
498
|
+
if (storedId) {
|
|
499
|
+
try {
|
|
500
|
+
execSync4(
|
|
501
|
+
`tmux display-message -t ${shellQuote(storedId)} -p "#{window_id}"`,
|
|
502
|
+
{ stdio: "pipe" }
|
|
503
|
+
);
|
|
504
|
+
execSync4(`tmux select-window -t ${shellQuote(storedId)}`, { stdio: "pipe" });
|
|
505
|
+
return false;
|
|
506
|
+
} catch {
|
|
507
|
+
}
|
|
501
508
|
}
|
|
502
509
|
} catch {
|
|
503
510
|
}
|
|
@@ -506,17 +513,23 @@ function ensureDashboard(tmuxSession, cwd) {
|
|
|
506
513
|
`tmux new-window -n "sisyphus-dashboard" -c ${shellQuote(cwd)} -P -F "#{window_id}"`,
|
|
507
514
|
{ encoding: "utf-8" }
|
|
508
515
|
).trim();
|
|
509
|
-
const cmd = `node ${shellQuote(tuiPath)} --cwd ${shellQuote(cwd)}`;
|
|
516
|
+
const cmd = `node ${shellQuote(tuiPath)} --cwd ${shellQuote(cwd)}; exit`;
|
|
510
517
|
execSync4(
|
|
511
518
|
`tmux send-keys -t ${shellQuote(windowId)} ${shellQuote(cmd)} Enter`
|
|
512
519
|
);
|
|
520
|
+
execSync4(
|
|
521
|
+
`tmux set-option -t ${shellQuote(tmuxSession)} @sisyphus_dashboard ${shellQuote(windowId)}`,
|
|
522
|
+
{ stdio: "pipe" }
|
|
523
|
+
);
|
|
513
524
|
return true;
|
|
514
525
|
}
|
|
515
526
|
function registerDashboard(program2) {
|
|
516
527
|
program2.command("dashboard").description("Launch the TUI dashboard for monitoring and managing sessions").action(async () => {
|
|
517
528
|
assertTmux();
|
|
518
|
-
const
|
|
519
|
-
|
|
529
|
+
const tuiPath = join3(import.meta.dirname, "tui.js");
|
|
530
|
+
execSync4(`node ${shellQuote(tuiPath)} --cwd ${shellQuote(process.cwd())}`, {
|
|
531
|
+
stdio: "inherit"
|
|
532
|
+
});
|
|
520
533
|
});
|
|
521
534
|
}
|
|
522
535
|
|
|
@@ -550,7 +563,7 @@ function registerStart(program2) {
|
|
|
550
563
|
}
|
|
551
564
|
try {
|
|
552
565
|
const tmuxSession = getTmuxSession();
|
|
553
|
-
if (
|
|
566
|
+
if (openDashboardWindow(tmuxSession, cwd)) {
|
|
554
567
|
console.log(`Dashboard opened in tmux window "sisyphus-dashboard"`);
|
|
555
568
|
}
|
|
556
569
|
} catch {
|
|
@@ -737,7 +750,8 @@ function registerContinue(program2) {
|
|
|
737
750
|
}
|
|
738
751
|
|
|
739
752
|
// src/cli/commands/status.ts
|
|
740
|
-
import {
|
|
753
|
+
import { execSync as execSync6 } from "child_process";
|
|
754
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
741
755
|
var COLOR_CODES = {
|
|
742
756
|
green: "\x1B[32m",
|
|
743
757
|
yellow: "\x1B[33m",
|
|
@@ -773,12 +787,17 @@ function inferOrchestratorPhase(session) {
|
|
|
773
787
|
return "starting";
|
|
774
788
|
}
|
|
775
789
|
}
|
|
776
|
-
function formatAgent(agent) {
|
|
790
|
+
function formatAgent(agent, verbose) {
|
|
777
791
|
const status = colorize(agent.status, agent.status);
|
|
778
792
|
const name = `${BOLD}${agent.name}${RESET}`;
|
|
779
793
|
const type = `${DIM}(${agent.agentType})${RESET}`;
|
|
780
794
|
const duration = formatDuration(agent.activeMs);
|
|
781
795
|
let line = ` ${agent.id} ${name} ${type} \u2014 ${status} ${DIM}(${duration})${RESET}`;
|
|
796
|
+
if (verbose && agent.instruction) {
|
|
797
|
+
const truncated = agent.instruction.length > 200 ? agent.instruction.slice(0, 200) + "..." : agent.instruction;
|
|
798
|
+
line += `
|
|
799
|
+
${DIM}Instruction: ${truncated}${RESET}`;
|
|
800
|
+
}
|
|
782
801
|
if (agent.reports.length > 0) {
|
|
783
802
|
for (const r of agent.reports) {
|
|
784
803
|
const label = r.type === "final" ? "Final" : "Update";
|
|
@@ -828,7 +847,33 @@ function readRoadmapTodos(cwd, sessionId) {
|
|
|
828
847
|
return [];
|
|
829
848
|
}
|
|
830
849
|
}
|
|
831
|
-
function
|
|
850
|
+
function readFullRoadmap(cwd, sessionId) {
|
|
851
|
+
try {
|
|
852
|
+
return readFileSync3(roadmapPath(cwd, sessionId), "utf8");
|
|
853
|
+
} catch {
|
|
854
|
+
return null;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
function readCycleLog(cwd, sessionId, cycle) {
|
|
858
|
+
try {
|
|
859
|
+
const path = cycleLogPath(cwd, sessionId, cycle);
|
|
860
|
+
if (!existsSync4(path)) return null;
|
|
861
|
+
return readFileSync3(path, "utf8");
|
|
862
|
+
} catch {
|
|
863
|
+
return null;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
function capturePaneOutput(paneId, lines = 50) {
|
|
867
|
+
try {
|
|
868
|
+
return execSync6(
|
|
869
|
+
`tmux capture-pane -t "${paneId}" -p -S -${lines}`,
|
|
870
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
871
|
+
).trimEnd();
|
|
872
|
+
} catch {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function printSession(session, verbose) {
|
|
832
877
|
const status = colorize(session.status, session.status);
|
|
833
878
|
const sessionDuration = formatDuration(session.createdAt, session.completedAt);
|
|
834
879
|
console.log(`
|
|
@@ -836,7 +881,7 @@ ${BOLD}Session: ${session.id}${RESET}`);
|
|
|
836
881
|
console.log(` Status: ${status}`);
|
|
837
882
|
console.log(` Task: ${session.task}`);
|
|
838
883
|
if (session.context) {
|
|
839
|
-
const truncated = session.context.length > 120 ? session.context.slice(0, 120) + "..." : session.context;
|
|
884
|
+
const truncated = !verbose && session.context.length > 120 ? session.context.slice(0, 120) + "..." : session.context;
|
|
840
885
|
console.log(` Context: ${truncated}`);
|
|
841
886
|
}
|
|
842
887
|
console.log(` CWD: ${session.cwd}`);
|
|
@@ -857,14 +902,27 @@ ${BOLD}Active agents (${runningAgents.length}):${RESET}`);
|
|
|
857
902
|
const type = `${DIM}(${agent.agentType})${RESET}`;
|
|
858
903
|
const duration = formatDuration(agent.activeMs);
|
|
859
904
|
console.log(` ${agent.id} ${name} ${type} running ${duration}`);
|
|
905
|
+
if (verbose && agent.instruction) {
|
|
906
|
+
const truncated = agent.instruction.length > 200 ? agent.instruction.slice(0, 200) + "..." : agent.instruction;
|
|
907
|
+
console.log(` ${DIM}Instruction: ${truncated}${RESET}`);
|
|
908
|
+
}
|
|
860
909
|
}
|
|
861
910
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
911
|
+
if (verbose) {
|
|
912
|
+
const roadmap = readFullRoadmap(session.cwd, session.id);
|
|
913
|
+
if (roadmap) {
|
|
914
|
+
console.log(`
|
|
915
|
+
${BOLD}Roadmap:${RESET}`);
|
|
916
|
+
console.log(roadmap);
|
|
917
|
+
}
|
|
918
|
+
} else {
|
|
919
|
+
const todos = readRoadmapTodos(session.cwd, session.id);
|
|
920
|
+
if (todos.length > 0) {
|
|
921
|
+
console.log(`
|
|
865
922
|
${BOLD}Remaining (${todos.length} unchecked):${RESET}`);
|
|
866
|
-
|
|
867
|
-
|
|
923
|
+
for (const todo of todos) {
|
|
924
|
+
console.log(` - ${todo}`);
|
|
925
|
+
}
|
|
868
926
|
}
|
|
869
927
|
}
|
|
870
928
|
if (session.orchestratorCycles.length > 0) {
|
|
@@ -875,25 +933,68 @@ ${BOLD}Remaining (${todos.length} unchecked):${RESET}`);
|
|
|
875
933
|
const isLast = i === cycles.length - 1;
|
|
876
934
|
const phase = isLast && session.status === "active" ? inferOrchestratorPhase(session) : void 0;
|
|
877
935
|
console.log(formatCycle(cycles[i], phase));
|
|
936
|
+
if (verbose) {
|
|
937
|
+
const log = readCycleLog(session.cwd, session.id, cycles[i].cycle);
|
|
938
|
+
if (log) {
|
|
939
|
+
const lines = log.split("\n");
|
|
940
|
+
const preview = lines.slice(0, 20).join("\n");
|
|
941
|
+
console.log(` ${DIM}--- cycle log ---${RESET}`);
|
|
942
|
+
for (const line of preview.split("\n")) {
|
|
943
|
+
console.log(` ${DIM}${line}${RESET}`);
|
|
944
|
+
}
|
|
945
|
+
if (lines.length > 20) {
|
|
946
|
+
console.log(` ${DIM}... (${lines.length - 20} more lines)${RESET}`);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
}
|
|
878
950
|
}
|
|
879
951
|
}
|
|
880
952
|
if (session.agents.length > 0) {
|
|
881
953
|
console.log(`
|
|
882
954
|
${BOLD}Agents:${RESET}`);
|
|
883
955
|
for (const agent of session.agents) {
|
|
884
|
-
console.log(formatAgent(agent));
|
|
956
|
+
console.log(formatAgent(agent, verbose));
|
|
885
957
|
}
|
|
886
958
|
}
|
|
959
|
+
if (verbose) {
|
|
960
|
+
const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];
|
|
961
|
+
if (lastCycle && !lastCycle.completedAt && lastCycle.paneId) {
|
|
962
|
+
const output = capturePaneOutput(lastCycle.paneId);
|
|
963
|
+
if (output) {
|
|
964
|
+
console.log(`
|
|
965
|
+
<orchestrator-pane-output lines="50">`);
|
|
966
|
+
console.log(output);
|
|
967
|
+
console.log(`</orchestrator-pane-output>`);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
for (const agent of runningAgents) {
|
|
971
|
+
if (agent.paneId) {
|
|
972
|
+
const output = capturePaneOutput(agent.paneId, 30);
|
|
973
|
+
if (output) {
|
|
974
|
+
console.log(`
|
|
975
|
+
<agent-pane-output agent="${agent.id}" name="${agent.name}" lines="30">`);
|
|
976
|
+
console.log(output);
|
|
977
|
+
console.log(`</agent-pane-output>`);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
if (verbose && session.completionReport) {
|
|
983
|
+
console.log(`
|
|
984
|
+
${BOLD}Completion Report:${RESET}`);
|
|
985
|
+
console.log(session.completionReport);
|
|
986
|
+
}
|
|
887
987
|
}
|
|
888
988
|
function registerStatus(program2) {
|
|
889
|
-
program2.command("status").description("Show session status").argument("[session-id]", "Session ID (defaults to SISYPHUS_SESSION_ID env)").action(async (sessionIdArg) => {
|
|
989
|
+
program2.command("status").description("Show session status").argument("[session-id]", "Session ID (defaults to SISYPHUS_SESSION_ID env)").option("-v, --verbose", "Show detailed output (roadmap, pane output, agent instructions)").action(async (sessionIdArg, opts) => {
|
|
890
990
|
const sessionId = sessionIdArg ?? process.env.SISYPHUS_SESSION_ID;
|
|
991
|
+
const verbose = opts?.verbose ?? false;
|
|
891
992
|
const request = { type: "status", sessionId };
|
|
892
993
|
const response = await sendRequest(request);
|
|
893
994
|
if (response.ok) {
|
|
894
995
|
const session = response.data?.session;
|
|
895
996
|
if (session) {
|
|
896
|
-
printSession(session);
|
|
997
|
+
printSession(session, verbose);
|
|
897
998
|
} else {
|
|
898
999
|
console.log("No session found");
|
|
899
1000
|
}
|
|
@@ -1164,12 +1265,12 @@ function registerSetupKeybind(program2) {
|
|
|
1164
1265
|
}
|
|
1165
1266
|
|
|
1166
1267
|
// src/cli/commands/doctor.ts
|
|
1167
|
-
import { execSync as
|
|
1168
|
-
import { existsSync as
|
|
1268
|
+
import { execSync as execSync8 } from "child_process";
|
|
1269
|
+
import { existsSync as existsSync6, statSync } from "fs";
|
|
1169
1270
|
|
|
1170
1271
|
// src/cli/onboard.ts
|
|
1171
|
-
import { execSync as
|
|
1172
|
-
import { existsSync as
|
|
1272
|
+
import { execSync as execSync7 } from "child_process";
|
|
1273
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
1173
1274
|
import { homedir as homedir3 } from "os";
|
|
1174
1275
|
import { dirname as dirname2, join as join5 } from "path";
|
|
1175
1276
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1180,7 +1281,7 @@ function detectTerminal() {
|
|
|
1180
1281
|
}
|
|
1181
1282
|
function isTmuxAvailable() {
|
|
1182
1283
|
try {
|
|
1183
|
-
|
|
1284
|
+
execSync7("which tmux", { stdio: "pipe" });
|
|
1184
1285
|
return true;
|
|
1185
1286
|
} catch {
|
|
1186
1287
|
return false;
|
|
@@ -1188,7 +1289,7 @@ function isTmuxAvailable() {
|
|
|
1188
1289
|
}
|
|
1189
1290
|
function isBrewAvailable() {
|
|
1190
1291
|
try {
|
|
1191
|
-
|
|
1292
|
+
execSync7("which brew", { stdio: "pipe" });
|
|
1192
1293
|
return true;
|
|
1193
1294
|
} catch {
|
|
1194
1295
|
return false;
|
|
@@ -1198,7 +1299,7 @@ function tryAutoInstallTmux() {
|
|
|
1198
1299
|
if (!isBrewAvailable()) return false;
|
|
1199
1300
|
try {
|
|
1200
1301
|
console.log(" Installing tmux via Homebrew...");
|
|
1201
|
-
|
|
1302
|
+
execSync7("brew install tmux", { stdio: "inherit" });
|
|
1202
1303
|
return isTmuxAvailable();
|
|
1203
1304
|
} catch {
|
|
1204
1305
|
return false;
|
|
@@ -1209,11 +1310,11 @@ function checkItermOptionKey() {
|
|
|
1209
1310
|
return { checked: false, allCorrect: true, incorrectProfiles: [] };
|
|
1210
1311
|
}
|
|
1211
1312
|
const plistPath2 = join5(homedir3(), "Library", "Preferences", "com.googlecode.iterm2.plist");
|
|
1212
|
-
if (!
|
|
1313
|
+
if (!existsSync5(plistPath2)) {
|
|
1213
1314
|
return { checked: false, allCorrect: false, incorrectProfiles: [] };
|
|
1214
1315
|
}
|
|
1215
1316
|
try {
|
|
1216
|
-
const json =
|
|
1317
|
+
const json = execSync7(
|
|
1217
1318
|
`plutil -extract "New Bookmarks" json -o - "${plistPath2}"`,
|
|
1218
1319
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1219
1320
|
);
|
|
@@ -1233,7 +1334,7 @@ function checkItermOptionKey() {
|
|
|
1233
1334
|
}
|
|
1234
1335
|
}
|
|
1235
1336
|
function hasExistingTmuxConf() {
|
|
1236
|
-
return
|
|
1337
|
+
return existsSync5(join5(homedir3(), ".tmux.conf")) || existsSync5(join5(homedir3(), ".config", "tmux", "tmux.conf"));
|
|
1237
1338
|
}
|
|
1238
1339
|
var TMUX_DEFAULTS = `# Sensible tmux defaults (installed by sisyphus)
|
|
1239
1340
|
# Customize freely \u2014 sisyphus won't overwrite this file.
|
|
@@ -1263,6 +1364,40 @@ set -g set-clipboard on
|
|
|
1263
1364
|
|
|
1264
1365
|
# Focus events (for editors)
|
|
1265
1366
|
set -g focus-events on
|
|
1367
|
+
|
|
1368
|
+
# --- Pane navigation (no prefix needed) ---
|
|
1369
|
+
bind -n C-h select-pane -L
|
|
1370
|
+
bind -n C-j select-pane -D
|
|
1371
|
+
bind -n C-k select-pane -U
|
|
1372
|
+
bind -n C-l select-pane -R
|
|
1373
|
+
|
|
1374
|
+
# --- Window navigation (no prefix needed) ---
|
|
1375
|
+
bind -n C-n next-window
|
|
1376
|
+
bind -n C-p previous-window
|
|
1377
|
+
|
|
1378
|
+
# --- New window / splits preserve cwd ---
|
|
1379
|
+
bind c new-window -c "#{pane_current_path}"
|
|
1380
|
+
bind '"' split-window -v -c "#{pane_current_path}"
|
|
1381
|
+
bind % split-window -h -c "#{pane_current_path}"
|
|
1382
|
+
|
|
1383
|
+
# --- Kill pane + rebalance ---
|
|
1384
|
+
bind x kill-pane \\; select-layout even-horizontal
|
|
1385
|
+
|
|
1386
|
+
# --- Auto-rebalance on pane close ---
|
|
1387
|
+
set-hook -g after-kill-pane "select-layout even-horizontal"
|
|
1388
|
+
set-hook -g pane-exited "select-layout even-horizontal"
|
|
1389
|
+
|
|
1390
|
+
# --- Manual re-tile ---
|
|
1391
|
+
bind = select-layout even-horizontal
|
|
1392
|
+
|
|
1393
|
+
# --- Scroll (no prefix needed) ---
|
|
1394
|
+
bind -n C-u copy-mode \\; send-keys -X halfpage-up
|
|
1395
|
+
bind -n C-d copy-mode \\; send-keys -X halfpage-down
|
|
1396
|
+
|
|
1397
|
+
# --- Vi copy mode ---
|
|
1398
|
+
setw -g mode-keys vi
|
|
1399
|
+
bind -T copy-mode-vi v send-keys -X begin-selection
|
|
1400
|
+
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
|
|
1266
1401
|
`;
|
|
1267
1402
|
function writeTmuxDefaults() {
|
|
1268
1403
|
const confPath = join5(homedir3(), ".tmux.conf");
|
|
@@ -1270,7 +1405,7 @@ function writeTmuxDefaults() {
|
|
|
1270
1405
|
}
|
|
1271
1406
|
function isNvimAvailable() {
|
|
1272
1407
|
try {
|
|
1273
|
-
|
|
1408
|
+
execSync7("which nvim", { stdio: "pipe" });
|
|
1274
1409
|
return true;
|
|
1275
1410
|
} catch {
|
|
1276
1411
|
return false;
|
|
@@ -1278,13 +1413,13 @@ function isNvimAvailable() {
|
|
|
1278
1413
|
}
|
|
1279
1414
|
function getNvimVersion() {
|
|
1280
1415
|
try {
|
|
1281
|
-
return
|
|
1416
|
+
return execSync7("nvim --version", { encoding: "utf-8", stdio: "pipe" }).split("\n")[0]?.replace("NVIM ", "") || "unknown";
|
|
1282
1417
|
} catch {
|
|
1283
1418
|
return "unknown";
|
|
1284
1419
|
}
|
|
1285
1420
|
}
|
|
1286
1421
|
function hasLazyVimConfig() {
|
|
1287
|
-
return
|
|
1422
|
+
return existsSync5(join5(homedir3(), ".config", "nvim", "lazy-lock.json"));
|
|
1288
1423
|
}
|
|
1289
1424
|
function tryAutoInstallNvim() {
|
|
1290
1425
|
if (isNvimAvailable()) {
|
|
@@ -1295,7 +1430,7 @@ function tryAutoInstallNvim() {
|
|
|
1295
1430
|
}
|
|
1296
1431
|
try {
|
|
1297
1432
|
console.log(" Installing neovim via Homebrew...");
|
|
1298
|
-
|
|
1433
|
+
execSync7("brew install neovim", { stdio: "inherit" });
|
|
1299
1434
|
} catch {
|
|
1300
1435
|
return { installed: false, autoInstalled: false, version: "", lazyVimInstalled: false };
|
|
1301
1436
|
}
|
|
@@ -1304,13 +1439,13 @@ function tryAutoInstallNvim() {
|
|
|
1304
1439
|
}
|
|
1305
1440
|
const nvimConfigDir = join5(homedir3(), ".config", "nvim");
|
|
1306
1441
|
let lazyVimInstalled = false;
|
|
1307
|
-
if (!
|
|
1442
|
+
if (!existsSync5(nvimConfigDir)) {
|
|
1308
1443
|
try {
|
|
1309
1444
|
console.log(" Cloning LazyVim starter config...");
|
|
1310
|
-
|
|
1445
|
+
execSync7(`git clone https://github.com/LazyVim/starter ${nvimConfigDir}`, { stdio: "inherit" });
|
|
1311
1446
|
const gitDir = join5(nvimConfigDir, ".git");
|
|
1312
|
-
if (
|
|
1313
|
-
|
|
1447
|
+
if (existsSync5(gitDir)) {
|
|
1448
|
+
execSync7(`rm -rf "${gitDir}"`, { stdio: "pipe" });
|
|
1314
1449
|
}
|
|
1315
1450
|
lazyVimInstalled = true;
|
|
1316
1451
|
} catch {
|
|
@@ -1326,15 +1461,15 @@ function bundledBeginCommandPath() {
|
|
|
1326
1461
|
return join5(distDir, "templates", "begin.md");
|
|
1327
1462
|
}
|
|
1328
1463
|
function isBeginCommandInstalled() {
|
|
1329
|
-
return
|
|
1464
|
+
return existsSync5(beginCommandPath());
|
|
1330
1465
|
}
|
|
1331
1466
|
function installBeginCommand() {
|
|
1332
1467
|
const dest = beginCommandPath();
|
|
1333
|
-
if (
|
|
1468
|
+
if (existsSync5(dest)) {
|
|
1334
1469
|
return { installed: true, autoInstalled: false, path: dest };
|
|
1335
1470
|
}
|
|
1336
1471
|
const src = bundledBeginCommandPath();
|
|
1337
|
-
if (!
|
|
1472
|
+
if (!existsSync5(src)) {
|
|
1338
1473
|
return { installed: false, autoInstalled: false, path: dest };
|
|
1339
1474
|
}
|
|
1340
1475
|
try {
|
|
@@ -1378,7 +1513,7 @@ function checkNodeVersion() {
|
|
|
1378
1513
|
}
|
|
1379
1514
|
function checkClaudeCli() {
|
|
1380
1515
|
try {
|
|
1381
|
-
|
|
1516
|
+
execSync8("which claude", { stdio: "pipe" });
|
|
1382
1517
|
return { name: "Claude CLI", status: "ok", detail: "Found on PATH" };
|
|
1383
1518
|
} catch {
|
|
1384
1519
|
return {
|
|
@@ -1391,7 +1526,7 @@ function checkClaudeCli() {
|
|
|
1391
1526
|
}
|
|
1392
1527
|
function checkGit() {
|
|
1393
1528
|
try {
|
|
1394
|
-
const version =
|
|
1529
|
+
const version = execSync8("git --version", { encoding: "utf-8", stdio: "pipe" }).trim();
|
|
1395
1530
|
return { name: "git", status: "ok", detail: version };
|
|
1396
1531
|
} catch {
|
|
1397
1532
|
return { name: "git", status: "fail", detail: "Not found on PATH", fix: "Install git: https://git-scm.com/downloads" };
|
|
@@ -1399,7 +1534,7 @@ function checkGit() {
|
|
|
1399
1534
|
}
|
|
1400
1535
|
function checkTmuxVersion() {
|
|
1401
1536
|
try {
|
|
1402
|
-
const version =
|
|
1537
|
+
const version = execSync8("tmux -V", { encoding: "utf-8", stdio: "pipe" }).trim();
|
|
1403
1538
|
const match = version.match(/(\d+\.\d+)/);
|
|
1404
1539
|
if (!match) return { name: "tmux version", status: "warn", detail: `Could not parse version: ${version}` };
|
|
1405
1540
|
const ver = parseFloat(match[1]);
|
|
@@ -1425,7 +1560,7 @@ function checkDaemonInstalled() {
|
|
|
1425
1560
|
};
|
|
1426
1561
|
}
|
|
1427
1562
|
const pid = daemonPidPath();
|
|
1428
|
-
if (
|
|
1563
|
+
if (existsSync6(pid)) {
|
|
1429
1564
|
return { name: "Daemon setup", status: "ok", detail: `PID file found at ${pid}` };
|
|
1430
1565
|
}
|
|
1431
1566
|
return {
|
|
@@ -1437,7 +1572,7 @@ function checkDaemonInstalled() {
|
|
|
1437
1572
|
}
|
|
1438
1573
|
function checkDaemonRunning() {
|
|
1439
1574
|
const pid = daemonPidPath();
|
|
1440
|
-
if (!
|
|
1575
|
+
if (!existsSync6(pid)) {
|
|
1441
1576
|
const fix = process.platform === "darwin" ? "launchctl load -w ~/Library/LaunchAgents/com.sisyphus.daemon.plist" : "sisyphusd & \u2014 or check if the process is running";
|
|
1442
1577
|
return {
|
|
1443
1578
|
name: "Daemon process",
|
|
@@ -1448,7 +1583,7 @@ function checkDaemonRunning() {
|
|
|
1448
1583
|
}
|
|
1449
1584
|
try {
|
|
1450
1585
|
const sock = socketPath();
|
|
1451
|
-
|
|
1586
|
+
execSync8(`test -S "${sock}"`, { stdio: "pipe" });
|
|
1452
1587
|
return { name: "Daemon process", status: "ok", detail: `Socket at ${sock}` };
|
|
1453
1588
|
} catch {
|
|
1454
1589
|
return {
|
|
@@ -1461,13 +1596,13 @@ function checkDaemonRunning() {
|
|
|
1461
1596
|
}
|
|
1462
1597
|
function checkTmux() {
|
|
1463
1598
|
try {
|
|
1464
|
-
|
|
1599
|
+
execSync8("which tmux", { stdio: "pipe" });
|
|
1465
1600
|
} catch {
|
|
1466
1601
|
const installHint = process.platform === "darwin" ? "brew install tmux" : "apt install tmux (Debian/Ubuntu) or your package manager";
|
|
1467
1602
|
return { name: "tmux", status: "fail", detail: "Not found on PATH", fix: installHint };
|
|
1468
1603
|
}
|
|
1469
1604
|
try {
|
|
1470
|
-
|
|
1605
|
+
execSync8("tmux list-sessions", { stdio: "pipe" });
|
|
1471
1606
|
return { name: "tmux", status: "ok", detail: "Running" };
|
|
1472
1607
|
} catch {
|
|
1473
1608
|
return { name: "tmux", status: "warn", detail: "Installed but no server running" };
|
|
@@ -1475,7 +1610,7 @@ function checkTmux() {
|
|
|
1475
1610
|
}
|
|
1476
1611
|
function checkCycleScript() {
|
|
1477
1612
|
const path = cycleScriptPath();
|
|
1478
|
-
if (!
|
|
1613
|
+
if (!existsSync6(path)) {
|
|
1479
1614
|
return {
|
|
1480
1615
|
name: "Cycle script",
|
|
1481
1616
|
status: "fail",
|
|
@@ -1500,7 +1635,7 @@ function checkCycleScript() {
|
|
|
1500
1635
|
function checkTmuxKeybind() {
|
|
1501
1636
|
const existing = getExistingBinding(DEFAULT_KEY);
|
|
1502
1637
|
if (existing === null) {
|
|
1503
|
-
if (
|
|
1638
|
+
if (existsSync6(sisyphusTmuxConfPath())) {
|
|
1504
1639
|
return {
|
|
1505
1640
|
name: `Tmux keybind (${DEFAULT_KEY})`,
|
|
1506
1641
|
status: "warn",
|
|
@@ -1526,7 +1661,7 @@ function checkTmuxKeybind() {
|
|
|
1526
1661
|
}
|
|
1527
1662
|
function checkGlobalDir() {
|
|
1528
1663
|
const dir = globalDir();
|
|
1529
|
-
if (
|
|
1664
|
+
if (existsSync6(dir)) {
|
|
1530
1665
|
return { name: "Data directory", status: "ok", detail: dir };
|
|
1531
1666
|
}
|
|
1532
1667
|
return { name: "Data directory", status: "warn", detail: `${dir} does not exist (created on first use)` };
|
|
@@ -1580,7 +1715,7 @@ function checkNvim() {
|
|
|
1580
1715
|
return { name: "nvim", status: "warn", detail: "Not installed", fix };
|
|
1581
1716
|
}
|
|
1582
1717
|
try {
|
|
1583
|
-
const version =
|
|
1718
|
+
const version = execSync8("nvim --version", { encoding: "utf-8", stdio: "pipe" }).split("\n")[0]?.replace("NVIM ", "");
|
|
1584
1719
|
return { name: "nvim", status: "ok", detail: version ?? "installed" };
|
|
1585
1720
|
} catch {
|
|
1586
1721
|
return { name: "nvim", status: "ok", detail: "installed" };
|
|
@@ -1634,6 +1769,12 @@ function registerCompanionContext(program2) {
|
|
|
1634
1769
|
}
|
|
1635
1770
|
|
|
1636
1771
|
// src/cli/commands/getting-started.ts
|
|
1772
|
+
import { execSync as execSync9 } from "child_process";
|
|
1773
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
1774
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1775
|
+
function templatePath(name) {
|
|
1776
|
+
return join6(dirname3(fileURLToPath3(import.meta.url)), "templates", name);
|
|
1777
|
+
}
|
|
1637
1778
|
function isClaudeCode() {
|
|
1638
1779
|
return !!process.env["CLAUDECODE"];
|
|
1639
1780
|
}
|
|
@@ -1678,7 +1819,7 @@ function printStep0() {
|
|
|
1678
1819
|
|
|
1679
1820
|
## Tutorial Overview
|
|
1680
1821
|
|
|
1681
|
-
This tutorial has
|
|
1822
|
+
This tutorial has 6 steps. Share this overview so the user knows what's coming and can skip ahead:
|
|
1682
1823
|
|
|
1683
1824
|
| Step | Topic | Command |
|
|
1684
1825
|
|------|-------|---------|
|
|
@@ -1687,6 +1828,7 @@ This tutorial has 5 steps. Share this overview so the user knows what's coming a
|
|
|
1687
1828
|
| 2 | Nvim basics \u2014 open, save, quit (optional) | \`--tutorial 2\` |
|
|
1688
1829
|
| 3 | Sisyphus concepts \u2014 session model & keybinds | \`--tutorial 3\` |
|
|
1689
1830
|
| 4 | Live demo \u2014 launch and observe a real session | \`--tutorial 4\` |
|
|
1831
|
+
| 5 | What's next \u2014 real usage guidance & suggestions | \`--tutorial 5\` |
|
|
1690
1832
|
|
|
1691
1833
|
Tell the user they can skip to any step with \`sisyphus getting-started --tutorial <N>\`.
|
|
1692
1834
|
|
|
@@ -1776,9 +1918,12 @@ tmux split-window -h
|
|
|
1776
1918
|
Tell them: "I just split your terminal. You should see two panes side by side."
|
|
1777
1919
|
|
|
1778
1920
|
Explain navigation:
|
|
1779
|
-
- \`Ctrl
|
|
1780
|
-
- \`Ctrl
|
|
1781
|
-
-
|
|
1921
|
+
- \`Ctrl+l\`: move to the right pane
|
|
1922
|
+
- \`Ctrl+h\`: move to the left pane
|
|
1923
|
+
- \`Ctrl+j\`: move to the pane below
|
|
1924
|
+
- \`Ctrl+k\`: move to the pane above
|
|
1925
|
+
- No prefix key needed \u2014 just hold Ctrl and press the direction letter
|
|
1926
|
+
- For windows: \`Ctrl+n\` next window, \`Ctrl+p\` previous window
|
|
1782
1927
|
|
|
1783
1928
|
Ask them to try navigating between panes.
|
|
1784
1929
|
|
|
@@ -1795,11 +1940,14 @@ Or tell them they can type \`exit\` in the extra pane to close it.
|
|
|
1795
1940
|
|
|
1796
1941
|
- **Detach**: \`Ctrl-b d\` \u2014 leaves tmux running in background, returns to normal terminal
|
|
1797
1942
|
- **Reattach**: \`tmux attach\` (or \`tmux a\`) \u2014 reconnects to the running session
|
|
1798
|
-
- **Scroll
|
|
1943
|
+
- **Scroll up/down**: \`Ctrl+u\` / \`Ctrl+d\` \u2014 scroll half-page up/down (no prefix needed). Press \`q\` to exit scroll mode.
|
|
1944
|
+
- **New window**: \`Ctrl-b n\` \u2014 opens a new window in the current directory
|
|
1945
|
+
- **Kill pane**: \`Ctrl-b x\` \u2014 closes the current pane and rebalances layout
|
|
1946
|
+
- **Re-tile**: \`Ctrl-b =\` \u2014 rebalance all panes to equal widths
|
|
1799
1947
|
|
|
1800
1948
|
### 5. Verification
|
|
1801
1949
|
|
|
1802
|
-
Ask the user to confirm: "Can you navigate between panes with Ctrl
|
|
1950
|
+
Ask the user to confirm: "Can you navigate between panes with Ctrl+h and Ctrl+l?"
|
|
1803
1951
|
|
|
1804
1952
|
Once confirmed, proceed:
|
|
1805
1953
|
\`\`\`
|
|
@@ -1819,40 +1967,39 @@ function printStep2() {
|
|
|
1819
1967
|
|
|
1820
1968
|
## Instructions for Claude
|
|
1821
1969
|
|
|
1822
|
-
This step is OPTIONAL. Nvim is useful for reviewing
|
|
1970
|
+
This step is OPTIONAL. Nvim is useful for reviewing and editing files when you jump into agent panes, but not required.
|
|
1971
|
+
|
|
1972
|
+
Note: The sisyphus dashboard has keys that auto-open files in nvim \u2014 users don't need to know how to open files from the command line. Focus on what they'll need once they're INSIDE nvim.
|
|
1823
1973
|
|
|
1824
1974
|
### If nvim is NOT installed (nvimInstalled: false)
|
|
1825
1975
|
|
|
1826
|
-
Ask the user: "Neovim is handy for reviewing files in tmux panes. Want me to install it, or skip this step?"
|
|
1976
|
+
Ask the user: "Neovim is handy for reviewing and editing files in tmux panes. Want me to install it, or skip this step?"
|
|
1827
1977
|
|
|
1828
1978
|
- **Install**: Run \`brew install neovim\` (macOS) or suggest their package manager
|
|
1829
1979
|
- **Skip**: That's fine \u2014 they can use \`cat\`, \`less\`, or any editor they prefer. Proceed to step 3.
|
|
1830
1980
|
|
|
1831
1981
|
### If nvim IS installed (nvimInstalled: true)
|
|
1832
1982
|
|
|
1833
|
-
|
|
1983
|
+
Briefly explain the key concept \u2014 nvim has two modes:
|
|
1834
1984
|
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
3. **Quit without saving**: \`:q!\` (colon, q, exclamation mark, Enter)
|
|
1985
|
+
- **Normal mode** (default): Keys are commands, not text. This is where you navigate.
|
|
1986
|
+
- **Insert mode**: Press \`i\` to enter. Now you type normally. \`Esc\` goes back to normal.
|
|
1838
1987
|
|
|
1839
|
-
|
|
1988
|
+
Then tell the user: "I'm going to open an interactive tutorial file in a pane to your right. It walks you through everything \u2014 navigation, editing, saving. Follow the instructions inside the file."
|
|
1840
1989
|
|
|
1841
|
-
|
|
1990
|
+
Open the bundled tutorial file in a split pane:
|
|
1842
1991
|
\`\`\`
|
|
1843
|
-
|
|
1992
|
+
cp ${templatePath("nvim-tutorial.txt")} /tmp/sisyphus-nvim-tutorial.txt
|
|
1993
|
+
tmux split-window -h "nvim /tmp/sisyphus-nvim-tutorial.txt"
|
|
1844
1994
|
\`\`\`
|
|
1845
1995
|
|
|
1846
|
-
|
|
1847
|
-
1. Open it: \`nvim /tmp/sisyphus-tutorial-test.txt\`
|
|
1848
|
-
2. Look around (they're in normal mode \u2014 arrow keys work for navigation)
|
|
1849
|
-
3. Close it: type \`ZZ\`
|
|
1996
|
+
Tell them to click on the right pane (or \`Ctrl+l\`) and follow the instructions in the file. When they \`:wq\` or \`ZZ\`, the pane closes and they're back in Claude.
|
|
1850
1997
|
|
|
1851
|
-
Tell them: "
|
|
1998
|
+
Tell them: "When you jump into an agent's pane and the dashboard opens a file, you'll land in normal mode. Now you know how to look around, make edits, and get out."
|
|
1852
1999
|
|
|
1853
2000
|
### Verification
|
|
1854
2001
|
|
|
1855
|
-
Ask if they were able to
|
|
2002
|
+
Ask if they were able to edit and save the file (or if they skipped).
|
|
1856
2003
|
|
|
1857
2004
|
Proceed:
|
|
1858
2005
|
\`\`\`
|
|
@@ -1862,13 +2009,75 @@ sisyphus getting-started --tutorial 3
|
|
|
1862
2009
|
`);
|
|
1863
2010
|
}
|
|
1864
2011
|
function printStep3() {
|
|
2012
|
+
let rightOptionKeyStatus = "unknown";
|
|
2013
|
+
const terminal = detectTerminal();
|
|
2014
|
+
if (!terminal.isIterm) {
|
|
2015
|
+
rightOptionKeyStatus = "not-iterm";
|
|
2016
|
+
} else {
|
|
2017
|
+
const result = checkItermOptionKey();
|
|
2018
|
+
if (!result.checked) {
|
|
2019
|
+
rightOptionKeyStatus = "could-not-check";
|
|
2020
|
+
} else if (result.allCorrect) {
|
|
2021
|
+
rightOptionKeyStatus = "ok";
|
|
2022
|
+
} else {
|
|
2023
|
+
rightOptionKeyStatus = `incorrect:${result.incorrectProfiles.join(",")}`;
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
1865
2026
|
console.log(`
|
|
1866
2027
|
<claude-instructions>
|
|
1867
2028
|
# Sisyphus Getting Started \u2014 Step 3: Sisyphus Concepts & Keybinds
|
|
1868
2029
|
|
|
2030
|
+
## Environment Data
|
|
2031
|
+
- rightOptionKeyStatus: ${rightOptionKeyStatus}
|
|
2032
|
+
|
|
1869
2033
|
## Instructions for Claude
|
|
1870
2034
|
|
|
1871
|
-
### 1.
|
|
2035
|
+
### 1. CRITICAL FIRST: Right Option Key Setup
|
|
2036
|
+
|
|
2037
|
+
**This must be done before anything else.** Sisyphus keybinds use the Option key as "Meta". By default, macOS terminals send special characters when you press Option (e.g., Option+s types \`\xDF\`). We need the RIGHT Option key to send escape sequences instead.
|
|
2038
|
+
|
|
2039
|
+
**Check the environment data above:**
|
|
2040
|
+
|
|
2041
|
+
- **rightOptionKeyStatus: ok** \u2014 They're all set, briefly confirm and move on.
|
|
2042
|
+
|
|
2043
|
+
- **rightOptionKeyStatus: incorrect:ProfileName** \u2014 Walk them through the fix:
|
|
2044
|
+
|
|
2045
|
+
> Your Right Option key isn't configured correctly yet. Here's how to fix it:
|
|
2046
|
+
>
|
|
2047
|
+
> 1. Open **iTerm2 Settings** (Cmd+,)
|
|
2048
|
+
> 2. Go to **Profiles** \u2192 select your profile (shown above)
|
|
2049
|
+
> 3. Click the **Keys** tab
|
|
2050
|
+
> 4. At the bottom, find **Right Option Key**
|
|
2051
|
+
> 5. Change it from **Normal** to **Esc+**
|
|
2052
|
+
>
|
|
2053
|
+
> \`\`\`
|
|
2054
|
+
> \u250C\u2500 iTerm2 Settings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
2055
|
+
> \u2502 Profiles > Keys \u2502
|
|
2056
|
+
> \u2502 \u2502
|
|
2057
|
+
> \u2502 Right Option Key: \u2502
|
|
2058
|
+
> \u2502 \u25CB Normal (sends special chars like \xDF) \u2502
|
|
2059
|
+
> \u2502 \u25CF Esc+ (sends escape sequences) \u2190 \u2713 \u2502
|
|
2060
|
+
> \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
2061
|
+
> \`\`\`
|
|
2062
|
+
>
|
|
2063
|
+
> **Why right and not left?** You'll still want the left Option key for
|
|
2064
|
+
> typing special characters (accents, symbols). The right Option key
|
|
2065
|
+
> becomes your "Meta" key for tmux/sisyphus keybinds.
|
|
2066
|
+
|
|
2067
|
+
After they change it, have them verify by re-running \`sisyphus doctor\` \u2014 look for "Right Option Key: Esc+".
|
|
2068
|
+
|
|
2069
|
+
- **rightOptionKeyStatus: not-iterm** \u2014 They're not using iTerm2. Explain:
|
|
2070
|
+
> Sisyphus keybinds use Option as Meta. In iTerm2 this is configured via
|
|
2071
|
+
> "Right Option Key \u2192 Esc+". For your terminal, look for a similar setting
|
|
2072
|
+
> like "Option sends Meta" or "Option sends Esc+". Without this, pressing
|
|
2073
|
+
> Option+s will type a special character instead of triggering the keybind.
|
|
2074
|
+
|
|
2075
|
+
- **rightOptionKeyStatus: could-not-check** or **unknown** \u2014 Ask them to manually check:
|
|
2076
|
+
> Press Option+s in your terminal. If you see \`\xDF\` (or another special character),
|
|
2077
|
+
> your Option key needs to be reconfigured. In iTerm2: Settings \u2192 Profiles \u2192 Keys \u2192
|
|
2078
|
+
> Right Option Key \u2192 Esc+.
|
|
2079
|
+
|
|
2080
|
+
### 2. Explain the session model
|
|
1872
2081
|
|
|
1873
2082
|
This is the KEY concept. Use the diagram and be clear:
|
|
1874
2083
|
|
|
@@ -1876,7 +2085,7 @@ This is the KEY concept. Use the diagram and be clear:
|
|
|
1876
2085
|
YOUR tmux session ("work") Sisyphus tmux session ("sisyphus-abc123")
|
|
1877
2086
|
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
1878
2087
|
\u2502 \u2502 \u2502 Orch \u2502 Agent \u2502 Agent \u2502
|
|
1879
|
-
\u2502 Your normal work \u2502 \u2190\u2500\u2500\u2192
|
|
2088
|
+
\u2502 Your normal work \u2502 \u2190\u2500\u2500\u2192 \u2502 (yellow)\u2502 (blue) \u2502 (green) \u2502
|
|
1880
2089
|
\u2502 + dashboard \u2502 \u2502 \u2502 \u2502 \u2502
|
|
1881
2090
|
\u2502 \u2502 \u2502 Plans & \u2502 Writes \u2502 Writes \u2502
|
|
1882
2091
|
\u2502 \u2502 \u2502 assigns \u2502 code \u2502 tests \u2502
|
|
@@ -1890,40 +2099,36 @@ Key points:
|
|
|
1890
2099
|
- Your session stays clean \u2014 you get a **dashboard** for monitoring
|
|
1891
2100
|
- You can jump between your session and the sisyphus session to observe
|
|
1892
2101
|
|
|
1893
|
-
###
|
|
2102
|
+
### 3. Teach keybinds
|
|
1894
2103
|
|
|
1895
|
-
Two keybinds to remember:
|
|
2104
|
+
Two keybinds to remember (both use the RIGHT Option key):
|
|
1896
2105
|
|
|
1897
2106
|
| Keybind | Action |
|
|
1898
2107
|
|---------|--------|
|
|
1899
|
-
|
|
|
1900
|
-
|
|
|
1901
|
-
|
|
1902
|
-
"M" means "Meta" which is the Option key on macOS. So \`M-s\` = hold Option, press s.
|
|
2108
|
+
| Right Option + s | Cycle through sisyphus sessions |
|
|
2109
|
+
| Right Option + Shift + s | Jump back to dashboard |
|
|
1903
2110
|
|
|
1904
|
-
###
|
|
2111
|
+
### 4. Verify keybinds are installed
|
|
1905
2112
|
|
|
1906
2113
|
Run \`sisyphus doctor\` and check the output. Look for:
|
|
1907
2114
|
- "Cycle script" \u2014 should be \u2713
|
|
1908
2115
|
- "Tmux keybind" \u2014 should be \u2713
|
|
2116
|
+
- "Right Option Key" \u2014 should be "Esc+"
|
|
1909
2117
|
|
|
1910
|
-
If
|
|
2118
|
+
If cycle script or keybind is missing, run: \`sisyphus setup-keybind\`
|
|
1911
2119
|
|
|
1912
|
-
###
|
|
2120
|
+
### 5. Test the keybind
|
|
1913
2121
|
|
|
1914
|
-
Have the user try pressing
|
|
2122
|
+
Have the user try pressing Right Option + s. Nothing should happen yet (no sisyphus session running) \u2014 and that's fine. The important thing is no special character appears.
|
|
1915
2123
|
|
|
1916
|
-
If they
|
|
1917
|
-
- Their terminal needs to send Option as Esc+ (Meta)
|
|
1918
|
-
- iTerm2: Settings \u2192 Profiles \u2192 Keys \u2192 Right Option Key \u2192 Esc+
|
|
1919
|
-
- Other terminals: look for "Meta key" or "Option sends" in preferences
|
|
2124
|
+
If they see \`\xDF\` or similar, circle back to the Right Option Key setup above.
|
|
1920
2125
|
|
|
1921
|
-
###
|
|
2126
|
+
### 6. Verification
|
|
1922
2127
|
|
|
1923
2128
|
Confirm:
|
|
1924
2129
|
- They understand the two-session model (their session vs sisyphus session)
|
|
1925
|
-
- \`sisyphus doctor\` shows keybinds installed
|
|
1926
|
-
- Option+s doesn't produce a special character
|
|
2130
|
+
- \`sisyphus doctor\` shows keybinds installed AND Right Option Key: Esc+
|
|
2131
|
+
- Right Option + s doesn't produce a special character
|
|
1927
2132
|
|
|
1928
2133
|
Proceed:
|
|
1929
2134
|
\`\`\`
|
|
@@ -1946,72 +2151,561 @@ This is the grand finale \u2014 a live demo session.
|
|
|
1946
2151
|
Run \`sisyphus doctor\` first. If any checks are failing, help the user fix them before proceeding.
|
|
1947
2152
|
All core checks (tmux, daemon, keybinds) should be \u2713.
|
|
1948
2153
|
|
|
1949
|
-
### 2.
|
|
2154
|
+
### 2. BEFORE launching: Teach navigation
|
|
2155
|
+
|
|
2156
|
+
**This is critical.** When \`sisyphus start\` runs, it auto-opens the dashboard in a new tmux window. The user will suddenly be looking at the dashboard and may feel "stuck". Teach them how to navigate BEFORE launching:
|
|
2157
|
+
|
|
2158
|
+
Explain clearly:
|
|
1950
2159
|
|
|
1951
|
-
|
|
2160
|
+
> Before we launch, you need to know how to move between tmux windows. Right now you're in a window with Claude. When sisyphus starts, it'll open a dashboard in a new window. Think of windows like tabs:
|
|
2161
|
+
>
|
|
2162
|
+
> \`\`\`
|
|
2163
|
+
> Window 1 (you are here) Window 2 (dashboard)
|
|
2164
|
+
> \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
2165
|
+
> \u2502 Claude Code \u2502 \u2502 Sisyphus \u2502
|
|
2166
|
+
> \u2502 (this session) \u2502 \u2192 \u2502 Dashboard \u2502
|
|
2167
|
+
> \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
2168
|
+
> Ctrl+n \u2192 \u2190 Ctrl+p
|
|
2169
|
+
> \`\`\`
|
|
2170
|
+
>
|
|
2171
|
+
> - **\`Ctrl+n\`** \u2014 next window (go to dashboard)
|
|
2172
|
+
> - **\`Ctrl+p\`** \u2014 previous window (come back here)
|
|
2173
|
+
>
|
|
2174
|
+
> And remember from step 3:
|
|
2175
|
+
> - **Right Option + s** \u2014 jump to the sisyphus agent session (where you can watch agents work live)
|
|
2176
|
+
> - **Right Option + Shift + s** \u2014 jump back to dashboard
|
|
2177
|
+
|
|
2178
|
+
Have the user confirm they understand these keybinds before proceeding.
|
|
2179
|
+
|
|
2180
|
+
### 3. Set expectations, copy demo app, and launch
|
|
2181
|
+
|
|
2182
|
+
First, copy the demo todo app to a temp directory and init a git repo (sisyphus needs git):
|
|
2183
|
+
\`\`\`
|
|
2184
|
+
rm -rf /tmp/sisyphus-tutorial-demo
|
|
2185
|
+
cp -r ${templatePath("tutorial-demo")} /tmp/sisyphus-tutorial-demo
|
|
2186
|
+
git -C /tmp/sisyphus-tutorial-demo init
|
|
2187
|
+
git -C /tmp/sisyphus-tutorial-demo add -A
|
|
2188
|
+
git -C /tmp/sisyphus-tutorial-demo commit -m "Initial todo app"
|
|
1952
2189
|
\`\`\`
|
|
1953
|
-
|
|
2190
|
+
|
|
2191
|
+
Tell the user:
|
|
2192
|
+
|
|
2193
|
+
> I've set up a small todo app in /tmp/sisyphus-tutorial-demo \u2014 a Node.js API
|
|
2194
|
+
> with a few files. I'm going to launch sisyphus on it. Here's what will happen:
|
|
2195
|
+
> 1. The dashboard opens automatically (you'll be switched to it)
|
|
2196
|
+
> 2. Press **Ctrl+p** to come back here to Claude \u2014 I'll guide you through what to watch
|
|
2197
|
+
> 3. The session takes a few minutes. You can watch agents work live!
|
|
2198
|
+
|
|
2199
|
+
Then launch from the demo directory:
|
|
1954
2200
|
\`\`\`
|
|
2201
|
+
cd /tmp/sisyphus-tutorial-demo && sisyphus start "Add three improvements to this todo app: (1) add a priority field (high/medium/low) to todos, (2) add a GET /todos/stats endpoint that returns counts of total/done/pending todos, (3) add tests for the new features. Explain your thinking at each step." -c "TUTORIAL DEMO: A user is watching this session to learn how sisyphus works. Be EXTRA VERBOSE \u2014 explain your reasoning, narrate what you're doing, and make your planning visible. When spawning agents, give each agent context that this is a tutorial demo and they should explain their work clearly. Keep scope small: 2-3 agents, 1-2 cycles."
|
|
2202
|
+
\`\`\`
|
|
2203
|
+
|
|
2204
|
+
After launching, tell them:
|
|
2205
|
+
|
|
2206
|
+
> The dashboard just opened. Press **Ctrl+p** to come back here \u2014 I'll provide live commentary as the session runs so you know what's happening.
|
|
2207
|
+
|
|
2208
|
+
Wait for them to confirm they're back, then start live commentary.
|
|
2209
|
+
|
|
2210
|
+
### 4. Live commentary loop
|
|
2211
|
+
|
|
2212
|
+
**This is the most important part of the demo.** Don't just launch and wait \u2014 actively narrate.
|
|
1955
2213
|
|
|
1956
|
-
|
|
2214
|
+
Once the user is back, start a polling loop. Every ~45 seconds, run \`sisyphus status --verbose <session-id>\` and provide SHORT, contextual commentary about what's happening. The \`--verbose\` flag shows agent instructions, full roadmap, cycle logs, and live pane output from the orchestrator and running agents \u2014 use this rich data to narrate what's actually happening, not just phase names.
|
|
1957
2215
|
|
|
1958
|
-
|
|
2216
|
+
**How to narrate each phase:**
|
|
1959
2217
|
|
|
1960
|
-
**
|
|
1961
|
-
- The dashboard should auto-open. If not, run \`sisyphus dashboard\`
|
|
1962
|
-
- Point out: session status, cycle number, agent list
|
|
1963
|
-
- Tell them: "Watch the roadmap section \u2014 it updates as the orchestrator plans"
|
|
2218
|
+
- **Cycle 1, no agents yet**: "The orchestrator is reading the codebase and planning. It's figuring out how to split the work. Check the dashboard (\`Ctrl+n\`) \u2014 you'll see the roadmap updating."
|
|
1964
2219
|
|
|
1965
|
-
**
|
|
1966
|
-
- Have them press \`M-s\` (Option+s) to cycle to the sisyphus tmux session
|
|
1967
|
-
- They should see the orchestrator (yellow) working \u2014 reading files, planning
|
|
1968
|
-
- Point out: "Each pane is a separate Claude instance working independently"
|
|
2220
|
+
- **Agents spawning**: "Agents just spawned! You should see new panes appearing. Try \`Right Option + s\` to jump to the sisyphus session and watch them work. Each colored pane is an independent Claude instance."
|
|
1969
2221
|
|
|
1970
|
-
**
|
|
1971
|
-
- Press \`M-S\` (Option+Shift+s) to jump back to the dashboard
|
|
1972
|
-
- Or \`M-s\` to cycle through
|
|
2222
|
+
- **Agents working**: "Agent-001 is working on [X], Agent-002 is on [Y]. They're working in parallel \u2014 this is the key advantage of sisyphus. Jump over and watch if you like (\`Right Option + s\`)."
|
|
1973
2223
|
|
|
1974
|
-
**
|
|
1975
|
-
- As agents spawn, they'll appear in both the dashboard and the sisyphus session
|
|
1976
|
-
- Agents submit reports when done
|
|
1977
|
-
- The orchestrator respawns each cycle with fresh context
|
|
1978
|
-
- Eventually the session completes
|
|
2224
|
+
- **Agents submitting**: "Agent-001 just submitted its report! [N] more to go. When all agents finish, the orchestrator will respawn to review."
|
|
1979
2225
|
|
|
1980
|
-
|
|
2226
|
+
- **Between cycles**: "All agents done. The orchestrator is respawning with fresh context to review the reports and decide what's next. This is the cycle boundary \u2014 the orchestrator never runs out of context because it starts fresh each time."
|
|
2227
|
+
|
|
2228
|
+
- **Completion**: "The session is complete! Let me show you the results."
|
|
2229
|
+
|
|
2230
|
+
**Important:**
|
|
2231
|
+
- Keep commentary to 1-3 sentences per check \u2014 don't wall-of-text
|
|
2232
|
+
- Remind them of navigation keys when relevant ("jump over with Right Option + s to see this live")
|
|
2233
|
+
- If agents are still working with no change, say so briefly ("Still working... Agent-001 is the furthest along")
|
|
2234
|
+
- Reference specific agent names and tasks from the status output
|
|
2235
|
+
- Stop polling when status shows "completed"
|
|
2236
|
+
|
|
2237
|
+
Between polls, encourage the user to explore:
|
|
2238
|
+
> "While we wait, try jumping around: \`Ctrl+n\` for dashboard, \`Right Option + s\` for the agent session, \`Right Option + Shift + s\` to jump back. I'll keep narrating here."
|
|
2239
|
+
|
|
2240
|
+
### 5. After completion
|
|
1981
2241
|
|
|
1982
2242
|
Once the session shows "completed":
|
|
1983
2243
|
|
|
1984
|
-
-
|
|
1985
|
-
-
|
|
1986
|
-
-
|
|
2244
|
+
- Show them what the agents built: \`cd /tmp/sisyphus-tutorial-demo && git log --oneline\`
|
|
2245
|
+
- Run the tests to prove the work: \`cd /tmp/sisyphus-tutorial-demo && node --test test.js\`
|
|
2246
|
+
- Show the session artifacts: find the session dir in \`.sisyphus/sessions/\` and show \`roadmap.md\`
|
|
2247
|
+
- Explain: "Every session creates a roadmap, agent reports, and logs \u2014 all stored in .sisyphus/sessions/"
|
|
1987
2248
|
|
|
1988
|
-
###
|
|
2249
|
+
### 6. Proceed to wrap-up
|
|
1989
2250
|
|
|
1990
|
-
|
|
2251
|
+
Tell the user the demo is done. Then run:
|
|
2252
|
+
\`\`\`
|
|
2253
|
+
sisyphus getting-started --tutorial 5
|
|
2254
|
+
\`\`\`
|
|
2255
|
+
</claude-instructions>
|
|
2256
|
+
`);
|
|
2257
|
+
}
|
|
2258
|
+
function printStep5() {
|
|
2259
|
+
let recentCommits = "";
|
|
2260
|
+
let topLevelFiles = "";
|
|
2261
|
+
try {
|
|
2262
|
+
recentCommits = execSync9("git log --oneline -15 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
2263
|
+
} catch {
|
|
2264
|
+
}
|
|
2265
|
+
try {
|
|
2266
|
+
topLevelFiles = execSync9("ls -1 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
2267
|
+
} catch {
|
|
2268
|
+
}
|
|
2269
|
+
console.log(`
|
|
2270
|
+
<claude-instructions>
|
|
2271
|
+
# Sisyphus Getting Started \u2014 Step 5: What's Next
|
|
1991
2272
|
|
|
1992
|
-
|
|
1993
|
-
>
|
|
1994
|
-
|
|
1995
|
-
>
|
|
1996
|
-
|
|
1997
|
-
>
|
|
1998
|
-
|
|
1999
|
-
>
|
|
2273
|
+
## Codebase Context
|
|
2274
|
+
<recent-commits>
|
|
2275
|
+
${recentCommits || "(no git repo detected)"}
|
|
2276
|
+
</recent-commits>
|
|
2277
|
+
|
|
2278
|
+
<top-level-files>
|
|
2279
|
+
${topLevelFiles || "(could not list)"}
|
|
2280
|
+
</top-level-files>
|
|
2281
|
+
|
|
2282
|
+
## Instructions for Claude
|
|
2283
|
+
|
|
2284
|
+
### 1. Congratulate them
|
|
2285
|
+
|
|
2286
|
+
Tell them they've completed the tutorial and recap what they learned:
|
|
2287
|
+
- tmux basics (sessions, panes, navigation)
|
|
2288
|
+
- nvim basics for reviewing files
|
|
2289
|
+
- The sisyphus session model (separate tmux session for orchestrator + agents)
|
|
2290
|
+
- Monitoring with dashboard and keybinds
|
|
2291
|
+
- A live session lifecycle
|
|
2292
|
+
|
|
2293
|
+
### 2. Navigation cheat sheet
|
|
2294
|
+
|
|
2295
|
+
| Key | Action |
|
|
2296
|
+
|-----|--------|
|
|
2297
|
+
| \`Ctrl+n\` / \`Ctrl+p\` | Next/previous tmux window |
|
|
2298
|
+
| \`Ctrl+h/j/k/l\` | Navigate between panes |
|
|
2299
|
+
| \`Right Option + s\` | Jump to sisyphus agent session |
|
|
2300
|
+
| \`Right Option + Shift + s\` | Jump to dashboard |
|
|
2301
|
+
|
|
2302
|
+
### 3. How to use sisyphus for REAL work
|
|
2303
|
+
|
|
2304
|
+
This is the most important part. Explain clearly:
|
|
2305
|
+
|
|
2306
|
+
> **Sisyphus is for big, end-to-end features \u2014 the kind that need exploration,
|
|
2307
|
+
> planning, and parallel implementation across multiple systems.**
|
|
2000
2308
|
>
|
|
2001
|
-
>
|
|
2002
|
-
>
|
|
2003
|
-
|
|
2004
|
-
|
|
2309
|
+
> You don't need to define the task precisely. Broad is fine \u2014 the orchestrator
|
|
2310
|
+
> will explore the codebase, write specs, plan phases, and break it down itself.
|
|
2311
|
+
|
|
2312
|
+
**Real sisyphus sessions (from production use):**
|
|
2313
|
+
- "Design and implement a human-in-the-loop agent inbox system" \u2014 exploration, spec writing, DB schema, API endpoints, UI components, webhook integration, e2e validation
|
|
2314
|
+
- "Build multi-user organization features \u2014 invites, privilege gating, org switcher, workspace sharing, credit tracking" \u2014 touched auth, DB, API, UI, billing, permissions
|
|
2315
|
+
- "Rework all 5 worker onboarding templates to match production pipeline patterns" \u2014 mapped existing patterns, designed new architecture, implemented across templates, validated with e2e tests
|
|
2316
|
+
- "Autonomous failure detection system across 8 sequential phases" \u2014 monitoring, alerting, recovery, dashboard, with each phase building on the last
|
|
2317
|
+
- "Comprehensive code quality audit \u2014 find and fix dead code, null handling, useless fallbacks" \u2014 systematic codebase-wide analysis and cleanup
|
|
2318
|
+
- "Implement @requirements.md" \u2014 point it at a spec and let it go
|
|
2319
|
+
|
|
2320
|
+
**NOT good for sisyphus:**
|
|
2321
|
+
- Five unrelated small tasks bundled together ("fix the login bug, update the README, add a loading spinner") \u2014 these aren't one feature, they're a todo list
|
|
2322
|
+
- Something Claude Code in plan mode would handle \u2014 plan mode already handles substantial single-engineer work. If it fits in one Claude session, just do it directly.
|
|
2323
|
+
- Quick fixes, bug fixes, small refactors \u2014 use regular Claude Code
|
|
2324
|
+
|
|
2325
|
+
**How to start:**
|
|
2326
|
+
The easiest way is the \`/sisyphus:begin\` slash command inside Claude Code. Just tell Claude
|
|
2327
|
+
what you want to build and it'll hand it off to sisyphus with the right context.
|
|
2328
|
+
|
|
2329
|
+
Or directly: \`sisyphus start "your task" -c "any background context"\`
|
|
2330
|
+
|
|
2331
|
+
### 4. Suggest real tasks for THEIR codebase
|
|
2332
|
+
|
|
2333
|
+
Look at the recent commits and top-level files above. Based on what you can see of their project, suggest 2-3 concrete sisyphus-scale tasks they could try. Be specific to their codebase \u2014 reference actual directories, patterns, or areas you can see.
|
|
2334
|
+
|
|
2335
|
+
If there are no commits or files (e.g., they ran this from /tmp), skip this section.
|
|
2336
|
+
|
|
2337
|
+
Format as:
|
|
2338
|
+
> Based on your codebase, here are some tasks sisyphus would be great for:
|
|
2339
|
+
> - "..."
|
|
2340
|
+
> - "..."
|
|
2341
|
+
|
|
2342
|
+
### 5. There's more to learn
|
|
2343
|
+
|
|
2344
|
+
Tell them:
|
|
2345
|
+
|
|
2346
|
+
> There's actually a lot of depth to how sisyphus works \u2014 the design is intentional
|
|
2347
|
+
> and there's real reasoning behind why it does things the way it does. If you want
|
|
2348
|
+
> to understand the philosophy, or you want a deeper rundown on the dashboard,
|
|
2349
|
+
> monitoring, configuration, or how to steer sessions \u2014 just ask and I'll explain.
|
|
2350
|
+
|
|
2351
|
+
If the user says yes or asks to learn more, run \`sisyphus getting-started --explain\`
|
|
2352
|
+
and use its output to explain the system to them conversationally. Don't dump the whole
|
|
2353
|
+
thing \u2014 answer what they're curious about, using the reference as your source material.
|
|
2354
|
+
</claude-instructions>
|
|
2355
|
+
`);
|
|
2356
|
+
}
|
|
2357
|
+
function printExplain() {
|
|
2358
|
+
console.log(`
|
|
2359
|
+
<claude-instructions>
|
|
2360
|
+
# Sisyphus \u2014 Comprehensive Reference
|
|
2361
|
+
|
|
2362
|
+
This is a detailed reference for how sisyphus works. The user asked to understand
|
|
2363
|
+
sisyphus more deeply. Use this to answer their questions conversationally \u2014 don't dump
|
|
2364
|
+
the whole thing. Read through it, then respond to what they're curious about.
|
|
2365
|
+
|
|
2366
|
+
## Design Philosophy
|
|
2367
|
+
|
|
2368
|
+
Sisyphus is built on specific insights about how to get the best work out of LLM agents.
|
|
2369
|
+
These aren't arbitrary \u2014 each design decision solves a real failure mode.
|
|
2370
|
+
|
|
2371
|
+
### 1. The Orchestrator as "Human-in-the-Loop"
|
|
2372
|
+
|
|
2373
|
+
When you use Claude Code effectively, YOU are the orchestrator \u2014 you review work,
|
|
2374
|
+
steer direction, break problems down, and assign the next piece. Sisyphus automates
|
|
2375
|
+
that human role. The orchestrator does what a skilled developer does when prompting
|
|
2376
|
+
Claude: explore the codebase, understand the problem, write specs, plan phases,
|
|
2377
|
+
assign focused work, review results, and iterate.
|
|
2378
|
+
|
|
2379
|
+
The strategy layer mirrors how developers actually work on end-to-end features:
|
|
2380
|
+
explore, understand, spec, plan, implement, review, validate. The orchestrator
|
|
2381
|
+
follows this same workflow, but runs it with parallel agents.
|
|
2382
|
+
|
|
2383
|
+
### 2. Fresh Context Kills Shortcuts
|
|
2384
|
+
|
|
2385
|
+
The orchestrator is KILLED after every cycle and respawned fresh. This is the most
|
|
2386
|
+
important design decision.
|
|
2387
|
+
|
|
2388
|
+
When an LLM accumulates context over a long session, it starts taking shortcuts.
|
|
2389
|
+
It "knows" what it did earlier, so it skips re-reading, assumes things still hold,
|
|
2390
|
+
and builds on stale understanding. A fresh start forces honest reassessment every
|
|
2391
|
+
cycle \u2014 the orchestrator reads the actual state, not its memory of it.
|
|
2392
|
+
|
|
2393
|
+
This is inspired by adversarial training (think GANs) \u2014 better results come from
|
|
2394
|
+
adversarial pressure. Each fresh orchestrator effectively audits the previous cycle's
|
|
2395
|
+
work because it has no stake in defending prior decisions. It sees the roadmap, the
|
|
2396
|
+
reports, the code \u2014 and judges them with fresh eyes.
|
|
2397
|
+
|
|
2398
|
+
### 3. Single-Focus Agents
|
|
2399
|
+
|
|
2400
|
+
Each agent gets ONE task with a fully self-contained instruction. No context switching,
|
|
2401
|
+
no juggling multiple concerns, no "also while you're there could you..."
|
|
2402
|
+
|
|
2403
|
+
LLMs perform dramatically better when focused. An agent implementing a priority field
|
|
2404
|
+
doesn't think about the stats endpoint. It reads the relevant context, does its one
|
|
2405
|
+
thing well, and reports back. The orchestrator handles decomposition \u2014 agents handle
|
|
2406
|
+
execution.
|
|
2407
|
+
|
|
2408
|
+
### 4. Shared Context Directory (Saved Research)
|
|
2409
|
+
|
|
2410
|
+
Every session has a context/ directory where agents save research, specs, plans, and
|
|
2411
|
+
design docs. These files persist across ALL cycles and are visible to the orchestrator
|
|
2412
|
+
and subsequent agents.
|
|
2413
|
+
|
|
2414
|
+
This means research is never repeated. Cycle 1 agents explore and write findings to
|
|
2415
|
+
context/explore-auth-system.md. Cycle 3 agents read those findings and build on them.
|
|
2416
|
+
Knowledge accumulates even though the orchestrator itself is stateless.
|
|
2417
|
+
|
|
2418
|
+
### 5. Two-Layer Planning (Strategy + Roadmap)
|
|
2419
|
+
|
|
2420
|
+
The system maintains two documents at different abstraction levels:
|
|
2421
|
+
|
|
2422
|
+
**strategy.md** \u2014 The high-level problem-solving map. What phases exist, what gates
|
|
2423
|
+
between them, what backtrack paths exist. Updated every few cycles when the shape of
|
|
2424
|
+
work changes. Helps the orchestrator see the forest.
|
|
2425
|
+
|
|
2426
|
+
**roadmap.md** \u2014 Working memory. Updated every cycle. Current Stage, Exit Criteria,
|
|
2427
|
+
Active Context, Next Steps. The orchestrator reads this first each cycle to understand
|
|
2428
|
+
where things stand. Helps the orchestrator see the trees.
|
|
2429
|
+
|
|
2430
|
+
This prevents the failure mode where a single document becomes either too abstract
|
|
2431
|
+
to act on or too detailed to show the big picture.
|
|
2432
|
+
|
|
2433
|
+
### 6. Adversarial Review Is Built In
|
|
2434
|
+
|
|
2435
|
+
The orchestrator doesn't just implement \u2014 it runs mandatory critique cycles. After
|
|
2436
|
+
implementation, review agents attack different dimensions: code reuse, quality,
|
|
2437
|
+
efficiency, correctness. Fix agents address the findings. Re-review until only nits
|
|
2438
|
+
remain. Multiple agents auditing each other produces better results than any single
|
|
2439
|
+
agent reviewing its own work.
|
|
2440
|
+
|
|
2441
|
+
The rule: never let 2+ stages complete without critique. Small issues compound into
|
|
2442
|
+
architectural problems if unchecked.
|
|
2443
|
+
|
|
2444
|
+
### 7. Evidence Over Assumptions
|
|
2445
|
+
|
|
2446
|
+
Validation requires PROOF \u2014 command output, test results, HTTP responses. "The code
|
|
2447
|
+
looks correct" is not evidence. "All 14 tests pass" is. This catches the gap between
|
|
2448
|
+
code that looks right and code that works.
|
|
2449
|
+
|
|
2450
|
+
## Architecture Overview
|
|
2451
|
+
|
|
2452
|
+
\`\`\`
|
|
2453
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
2454
|
+
\u2502 USER'S TMUX SESSION \u2502
|
|
2455
|
+
\u2502 \u2502
|
|
2456
|
+
\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2457
|
+
\u2502 \u2502 Window 1: Claude Code \u2502 \u2502 Window 2: Dashboard (TUI) \u2502 \u2502
|
|
2458
|
+
\u2502 \u2502 \u2502 \u2502 \u2502 \u2502
|
|
2459
|
+
\u2502 \u2502 User's normal work \u2502 \u2502 Real-time session monitor \u2502 \u2502
|
|
2460
|
+
\u2502 \u2502 + this conversation \u2502 \u2502 Roadmap, agents, reports \u2502 \u2502
|
|
2461
|
+
\u2502 \u2502 \u2502 \u2502 Interactive controls \u2502 \u2502
|
|
2462
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2463
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
2464
|
+
\u2502 Right Option+s / Right Option+Shift+s
|
|
2465
|
+
\u25BC
|
|
2466
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
2467
|
+
\u2502 SISYPHUS TMUX SESSION \u2502
|
|
2468
|
+
\u2502 (created per sisyphus session) \u2502
|
|
2469
|
+
\u2502 \u2502
|
|
2470
|
+
\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2471
|
+
\u2502 \u2502 Orch \u2502 Agent \u2502 Agent \u2502 Agent \u2502 \u2190 panes \u2502
|
|
2472
|
+
\u2502 \u2502 (yellow) \u2502 (blue) \u2502 (green) \u2502 (magenta)\u2502 \u2502
|
|
2473
|
+
\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502
|
|
2474
|
+
\u2502 \u2502 Plans, \u2502 Impl \u2502 Tests \u2502 Docs \u2502 \u2190 each is a \u2502
|
|
2475
|
+
\u2502 \u2502 assigns, \u2502 feature \u2502 \u2502 \u2502 Claude Code \u2502
|
|
2476
|
+
\u2502 \u2502 reviews \u2502 \u2502 \u2502 \u2502 instance \u2502
|
|
2477
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2478
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
2479
|
+
\u2502
|
|
2480
|
+
\u25BC
|
|
2481
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
2482
|
+
\u2502 DAEMON (sisyphusd) \u2502
|
|
2483
|
+
\u2502 Background process via launchd \u2502
|
|
2484
|
+
\u2502 \u2502
|
|
2485
|
+
\u2502 Listens on ~/.sisyphus/daemon.sock \u2502
|
|
2486
|
+
\u2502 Manages session lifecycle, pane monitoring, state persistence \u2502
|
|
2487
|
+
\u2502 Polls panes to detect when agents/orchestrator finish \u2502
|
|
2488
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
2489
|
+
\`\`\`
|
|
2490
|
+
|
|
2491
|
+
## The Session Lifecycle (in detail)
|
|
2492
|
+
|
|
2493
|
+
\`\`\`
|
|
2494
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
2495
|
+
\u2502 SESSION LIFECYCLE \u2502
|
|
2496
|
+
\u2502 \u2502
|
|
2497
|
+
\u2502 sisyphus start "task" \u2502
|
|
2498
|
+
\u2502 \u2502 \u2502
|
|
2499
|
+
\u2502 \u25BC \u2502
|
|
2500
|
+
\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 spawn agents \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2501
|
+
\u2502 \u2502 Orch \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2192 \u2502 Agents work \u2502 \u2502
|
|
2502
|
+
\u2502 \u2502 plans \u2502 then yields \u2502 in parallel \u2502 \u2502
|
|
2503
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2504
|
+
\u2502 \u2502 \u2502 each calls \u2502
|
|
2505
|
+
\u2502 \u2502 orchestrator \u2502 sisyphus submit \u2502
|
|
2506
|
+
\u2502 \u2502 is KILLED \u2502 when done \u2502
|
|
2507
|
+
\u2502 \u2502 \u25BC \u2502
|
|
2508
|
+
\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2509
|
+
\u2502 \u2502 \u2502 All agents \u2502 \u2502
|
|
2510
|
+
\u2502 \u2502 \u2502 finished? \u2502 \u2502
|
|
2511
|
+
\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2512
|
+
\u2502 \u2502 \u2502 yes \u2502
|
|
2513
|
+
\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2514
|
+
\u2502 \u2502 \u25BC \u2502
|
|
2515
|
+
\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2516
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500 \u2502 Respawn \u2502 Fresh orchestrator with full state \u2502
|
|
2517
|
+
\u2502 next cycle \u2502 Orch \u2502 Reviews reports, plans next cycle \u2502
|
|
2518
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2519
|
+
\u2502 \u2502 \u2502
|
|
2520
|
+
\u2502 \u25BC \u2502
|
|
2521
|
+
\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2522
|
+
\u2502 \u2502 More work \u2502\u2500\u2500yes\u2500\u2500\u2192 \u2502 Spawn \u2502 \u2192 (loop) \u2502
|
|
2523
|
+
\u2502 \u2502 needed? \u2502 \u2502 agents \u2502 \u2502
|
|
2524
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2525
|
+
\u2502 \u2502 no \u2502
|
|
2526
|
+
\u2502 \u25BC \u2502
|
|
2527
|
+
\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2528
|
+
\u2502 \u2502 sisyphus \u2502 \u2502
|
|
2529
|
+
\u2502 \u2502 complete \u2502 \u2502
|
|
2530
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2531
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
2532
|
+
\`\`\`
|
|
2533
|
+
|
|
2534
|
+
**Key insight**: The orchestrator is STATELESS. It gets killed after each yield and
|
|
2535
|
+
respawned fresh with the complete session state (roadmap, agent reports, cycle history).
|
|
2536
|
+
This means it never runs out of context, no matter how many cycles a session takes.
|
|
2537
|
+
|
|
2538
|
+
## The Dashboard
|
|
2539
|
+
|
|
2540
|
+
The dashboard is a real-time TUI that shows session state. Launch with \`sisyphus dashboard\`
|
|
2541
|
+
or it auto-opens when a session starts.
|
|
2542
|
+
|
|
2543
|
+
**Dashboard sections:**
|
|
2544
|
+
- **Header**: Session ID, status, task description
|
|
2545
|
+
- **Roadmap**: Current strategic plan with checked/unchecked items
|
|
2546
|
+
- **Agents**: List of all agents with status, duration, and report summaries
|
|
2547
|
+
- **Cycles**: Orchestrator cycle history
|
|
2548
|
+
- **Messages**: Recent session messages
|
|
2549
|
+
|
|
2550
|
+
**Dashboard keys:**
|
|
2551
|
+
| Key | Action |
|
|
2552
|
+
|-----|--------|
|
|
2553
|
+
| \`m\` | Message the orchestrator (steer direction mid-session) |
|
|
2554
|
+
| \`w\` | Jump to the sisyphus tmux session (watch agents work) |
|
|
2555
|
+
| \`k\` | Kill the session |
|
|
2556
|
+
| \`r\` | Resume a paused/completed session |
|
|
2557
|
+
| \`q\` | Quit the dashboard |
|
|
2558
|
+
| \`\u2191/\u2193\` | Scroll through content |
|
|
2559
|
+
| \`Tab\` | Cycle through sections |
|
|
2560
|
+
|
|
2561
|
+
**The \`m\` key is the most powerful feature.** You can message the orchestrator at any time
|
|
2562
|
+
to course-correct: "Focus on the API layer first", "Skip the tests for now",
|
|
2563
|
+
"The approach for auth is wrong, use JWT instead". The orchestrator reads these
|
|
2564
|
+
messages when it respawns each cycle.
|
|
2565
|
+
|
|
2566
|
+
## Monitoring Strategy
|
|
2567
|
+
|
|
2568
|
+
Sisyphus sessions should be actively monitored. Here's what to watch for:
|
|
2569
|
+
|
|
2570
|
+
**Things that go wrong:**
|
|
2571
|
+
- Agents stuck waiting for user input (they're autonomous \u2014 they shouldn't need input)
|
|
2572
|
+
- Agents going down rabbit holes or working on the wrong thing
|
|
2573
|
+
- Merge conflicts between agents touching the same files
|
|
2574
|
+
- Orchestrator spawning too many agents or too few
|
|
2575
|
+
- Agents crashing or getting killed unexpectedly
|
|
2576
|
+
|
|
2577
|
+
**When to intervene:**
|
|
2578
|
+
- Use \`m\` in the dashboard to message the orchestrator with corrections
|
|
2579
|
+
- Use \`sisyphus kill <id>\` to stop a runaway session
|
|
2580
|
+
- Use \`sisyphus resume <id> "new instructions"\` to restart with different direction
|
|
2581
|
+
|
|
2582
|
+
**Useful monitoring commands:**
|
|
2583
|
+
\`\`\`
|
|
2584
|
+
sisyphus status <id> # Quick status check
|
|
2585
|
+
sisyphus status --verbose <id> # Full detail: roadmap, pane output, agent instructions
|
|
2586
|
+
sisyphus dashboard # Interactive TUI
|
|
2587
|
+
tail -f ~/.sisyphus/daemon.log # Daemon activity log
|
|
2588
|
+
\`\`\`
|
|
2589
|
+
|
|
2590
|
+
## The .sisyphus/ Directory
|
|
2591
|
+
|
|
2592
|
+
Everything sisyphus does lives in a \`.sisyphus/\` directory at the root of your project.
|
|
2593
|
+
This is project-local \u2014 each project gets its own. It contains:
|
|
2594
|
+
|
|
2595
|
+
\`\`\`
|
|
2596
|
+
.sisyphus/
|
|
2597
|
+
\u251C\u2500\u2500 config.json # Project-specific config (model, poll interval, etc.)
|
|
2598
|
+
\u251C\u2500\u2500 orchestrator.md # Optional custom orchestrator prompt override
|
|
2599
|
+
\u2514\u2500\u2500 sessions/
|
|
2600
|
+
\u251C\u2500\u2500 <session-id-1>/ # Each session gets its own directory
|
|
2601
|
+
\u251C\u2500\u2500 <session-id-2>/
|
|
2602
|
+
\u2514\u2500\u2500 ...
|
|
2603
|
+
\`\`\`
|
|
2604
|
+
|
|
2605
|
+
There's also a global directory at \`~/.sisyphus/\` for the daemon socket, PID file,
|
|
2606
|
+
logs, keybind scripts, and global config. But the session state \u2014 the roadmaps,
|
|
2607
|
+
reports, context files, cycle logs \u2014 all lives in your project's \`.sisyphus/sessions/\`.
|
|
2608
|
+
|
|
2609
|
+
## Session Files
|
|
2610
|
+
|
|
2611
|
+
Every session creates a directory at \`.sisyphus/sessions/<id>/\` with:
|
|
2612
|
+
|
|
2613
|
+
\`\`\`
|
|
2614
|
+
.sisyphus/sessions/<id>/
|
|
2615
|
+
\u251C\u2500\u2500 state.json # Session state (agents, cycles, status)
|
|
2616
|
+
\u251C\u2500\u2500 roadmap.md # Strategic plan (updated by orchestrator each cycle)
|
|
2617
|
+
\u251C\u2500\u2500 goal.md # Original task description
|
|
2618
|
+
\u251C\u2500\u2500 strategy.md # High-level strategy notes
|
|
2619
|
+
\u251C\u2500\u2500 logs/
|
|
2620
|
+
\u2502 \u251C\u2500\u2500 cycle-000.md # What the orchestrator did in cycle 0
|
|
2621
|
+
\u2502 \u251C\u2500\u2500 cycle-001.md # What it did in cycle 1, etc.
|
|
2622
|
+
\u2502 \u2514\u2500\u2500 ...
|
|
2623
|
+
\u251C\u2500\u2500 reports/
|
|
2624
|
+
\u2502 \u251C\u2500\u2500 agent-001-final.md # Agent's final report
|
|
2625
|
+
\u2502 \u251C\u2500\u2500 agent-002-update.md # Agent's progress update
|
|
2626
|
+
\u2502 \u2514\u2500\u2500 ...
|
|
2627
|
+
\u251C\u2500\u2500 prompts/ # System/user prompts sent to orchestrator and agents
|
|
2628
|
+
\u2514\u2500\u2500 context/ # Shared context files for agents
|
|
2629
|
+
\`\`\`
|
|
2630
|
+
|
|
2631
|
+
## Configuration
|
|
2632
|
+
|
|
2633
|
+
**Global config**: \`~/.sisyphus/config.json\`
|
|
2634
|
+
**Project config**: \`.sisyphus/config.json\` (overrides global)
|
|
2635
|
+
|
|
2636
|
+
Options:
|
|
2637
|
+
- \`model\` \u2014 Claude model for orchestrator and agents
|
|
2638
|
+
- \`orchestratorPrompt\` \u2014 Path to custom orchestrator prompt
|
|
2639
|
+
- \`pollIntervalMs\` \u2014 How often daemon checks pane status (default: 2000)
|
|
2640
|
+
|
|
2641
|
+
## Starting Sessions \u2014 Best Practices
|
|
2642
|
+
|
|
2643
|
+
**The /sisyphus:begin slash command** is the recommended way to start. Inside Claude Code:
|
|
2644
|
+
\`\`\`
|
|
2645
|
+
/sisyphus:begin
|
|
2646
|
+
\`\`\`
|
|
2647
|
+
Then describe your task. Claude will hand it off with the right context.
|
|
2648
|
+
|
|
2649
|
+
**Direct CLI:**
|
|
2650
|
+
\`\`\`
|
|
2651
|
+
sisyphus start "task description" -c "background context"
|
|
2652
|
+
sisyphus start "Implement @requirements.md" -n my-feature
|
|
2653
|
+
\`\`\`
|
|
2654
|
+
|
|
2655
|
+
**Reference files with @**: \`sisyphus start "Build @docs/spec.md"\` \u2014 the orchestrator
|
|
2656
|
+
will read the referenced file as part of its planning.
|
|
2657
|
+
|
|
2658
|
+
**The -c flag** adds background context the orchestrator sees but doesn't act on directly.
|
|
2659
|
+
Use it for constraints: \`-c "Don't modify the auth module, use the existing API"\`
|
|
2660
|
+
|
|
2661
|
+
**The -n flag** gives the session a human-readable name for easier tracking.
|
|
2662
|
+
|
|
2663
|
+
## CLI Command Reference
|
|
2664
|
+
|
|
2665
|
+
| Command | Purpose |
|
|
2666
|
+
|---------|---------|
|
|
2667
|
+
| \`sisyphus start "task"\` | Start a new session |
|
|
2668
|
+
| \`sisyphus status [id]\` | Check session status |
|
|
2669
|
+
| \`sisyphus status -v [id]\` | Detailed status with pane output |
|
|
2670
|
+
| \`sisyphus list\` | List all sessions |
|
|
2671
|
+
| \`sisyphus dashboard\` | Open the TUI dashboard |
|
|
2672
|
+
| \`sisyphus resume <id> "msg"\` | Resume with new instructions |
|
|
2673
|
+
| \`sisyphus kill <id>\` | Stop a session |
|
|
2674
|
+
| \`sisyphus doctor\` | Check installation health |
|
|
2675
|
+
| \`sisyphus setup\` | Run setup/onboarding |
|
|
2676
|
+
| \`sisyphus setup-keybind\` | Install tmux keybinds |
|
|
2677
|
+
|
|
2678
|
+
## Troubleshooting
|
|
2679
|
+
|
|
2680
|
+
**Daemon not running:**
|
|
2681
|
+
\`\`\`
|
|
2682
|
+
sisyphusd restart
|
|
2683
|
+
\`\`\`
|
|
2684
|
+
|
|
2685
|
+
**Keybinds not working (special characters appear):**
|
|
2686
|
+
iTerm2 \u2192 Settings \u2192 Profiles \u2192 Keys \u2192 Right Option Key \u2192 Esc+
|
|
2687
|
+
|
|
2688
|
+
**Agents stuck:** Check \`sisyphus status --verbose <id>\` to see pane output. If an
|
|
2689
|
+
agent is waiting for input, kill the session and restart with clearer instructions.
|
|
2690
|
+
|
|
2691
|
+
**Dashboard not opening:** Run \`sisyphus dashboard\` manually. Must be inside tmux.
|
|
2692
|
+
|
|
2693
|
+
**Session seems hung:** Check \`tail -20 ~/.sisyphus/daemon.log\` for errors.
|
|
2694
|
+
The daemon polls panes every 2s \u2014 if a pane dies unexpectedly, it'll be detected.
|
|
2005
2695
|
</claude-instructions>
|
|
2006
2696
|
`);
|
|
2007
2697
|
}
|
|
2008
|
-
var STEPS = [printStep0, printStep1, printStep2, printStep3, printStep4];
|
|
2698
|
+
var STEPS = [printStep0, printStep1, printStep2, printStep3, printStep4, printStep5];
|
|
2009
2699
|
function registerGettingStarted(program2) {
|
|
2010
|
-
program2.command("getting-started").description("Interactive tutorial (best with Claude Code)").option("--tutorial <step>", "Tutorial step (0-
|
|
2700
|
+
program2.command("getting-started").description("Interactive tutorial (best with Claude Code)").option("--tutorial <step>", "Tutorial step (0-5)", parseInt).option("--explain", "Comprehensive reference for how sisyphus works").action((opts) => {
|
|
2701
|
+
if (opts.explain) {
|
|
2702
|
+
printExplain();
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2011
2705
|
if (opts.tutorial !== void 0) {
|
|
2012
2706
|
const step = opts.tutorial;
|
|
2013
|
-
if (step < 0 || step >
|
|
2014
|
-
console.error(`Invalid tutorial step: ${opts.tutorial}. Must be 0-
|
|
2707
|
+
if (step < 0 || step > 5 || Number.isNaN(step)) {
|
|
2708
|
+
console.error(`Invalid tutorial step: ${opts.tutorial}. Must be 0-5.`);
|
|
2015
2709
|
process.exit(1);
|
|
2016
2710
|
}
|
|
2017
2711
|
STEPS[step]();
|
|
@@ -2026,8 +2720,8 @@ function registerGettingStarted(program2) {
|
|
|
2026
2720
|
}
|
|
2027
2721
|
|
|
2028
2722
|
// src/cli/commands/init.ts
|
|
2029
|
-
import { existsSync as
|
|
2030
|
-
import { join as
|
|
2723
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
2724
|
+
import { join as join7 } from "path";
|
|
2031
2725
|
var DEFAULT_CONFIG = {};
|
|
2032
2726
|
var ORCHESTRATOR_TEMPLATE = `# Custom Orchestrator Prompt
|
|
2033
2727
|
|
|
@@ -2038,9 +2732,9 @@ var ORCHESTRATOR_TEMPLATE = `# Custom Orchestrator Prompt
|
|
|
2038
2732
|
function registerInit(program2) {
|
|
2039
2733
|
program2.command("init").description("Initialize sisyphus configuration for this project").option("--orchestrator", "Also create a custom orchestrator prompt template").action((opts) => {
|
|
2040
2734
|
const cwd = process.cwd();
|
|
2041
|
-
const sisDir =
|
|
2042
|
-
const configPath =
|
|
2043
|
-
if (
|
|
2735
|
+
const sisDir = join7(cwd, ".sisyphus");
|
|
2736
|
+
const configPath = join7(sisDir, "config.json");
|
|
2737
|
+
if (existsSync7(configPath)) {
|
|
2044
2738
|
console.log(`Already initialized: ${configPath}`);
|
|
2045
2739
|
return;
|
|
2046
2740
|
}
|
|
@@ -2048,8 +2742,8 @@ function registerInit(program2) {
|
|
|
2048
2742
|
writeFileSync4(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n", "utf-8");
|
|
2049
2743
|
console.log(`Created ${configPath}`);
|
|
2050
2744
|
if (opts.orchestrator) {
|
|
2051
|
-
const orchPath =
|
|
2052
|
-
if (!
|
|
2745
|
+
const orchPath = join7(sisDir, "orchestrator.md");
|
|
2746
|
+
if (!existsSync7(orchPath)) {
|
|
2053
2747
|
writeFileSync4(orchPath, ORCHESTRATOR_TEMPLATE, "utf-8");
|
|
2054
2748
|
console.log(`Created ${orchPath}`);
|
|
2055
2749
|
}
|
|
@@ -2064,10 +2758,10 @@ function registerInit(program2) {
|
|
|
2064
2758
|
}
|
|
2065
2759
|
|
|
2066
2760
|
// src/cli/commands/setup.ts
|
|
2067
|
-
import { execSync as
|
|
2761
|
+
import { execSync as execSync10 } from "child_process";
|
|
2068
2762
|
function getTmuxVersion() {
|
|
2069
2763
|
try {
|
|
2070
|
-
return
|
|
2764
|
+
return execSync10("tmux -V", { encoding: "utf-8", stdio: "pipe" }).trim();
|
|
2071
2765
|
} catch {
|
|
2072
2766
|
return "installed";
|
|
2073
2767
|
}
|
|
@@ -2160,7 +2854,7 @@ if (nodeVersion < 22) {
|
|
|
2160
2854
|
var program = new Command();
|
|
2161
2855
|
program.name("sisyphus").description("tmux-integrated orchestration daemon for Claude Code").version(
|
|
2162
2856
|
JSON.parse(
|
|
2163
|
-
readFileSync5(
|
|
2857
|
+
readFileSync5(join8(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json"), "utf-8")
|
|
2164
2858
|
).version
|
|
2165
2859
|
);
|
|
2166
2860
|
program.configureHelp({
|
|
@@ -2203,7 +2897,7 @@ Run 'sisyphus getting-started' for a complete usage guide.
|
|
|
2203
2897
|
var args = process.argv.slice(2);
|
|
2204
2898
|
var firstArg = args[0];
|
|
2205
2899
|
var skipWelcome = ["doctor", "getting-started", "help", "--help", "-h", "init", "setup", "uninstall", "--version", "-V"];
|
|
2206
|
-
if (!
|
|
2900
|
+
if (!existsSync8(globalDir()) && firstArg && !skipWelcome.includes(firstArg)) {
|
|
2207
2901
|
mkdirSync5(globalDir(), { recursive: true });
|
|
2208
2902
|
console.log("");
|
|
2209
2903
|
console.log(" Welcome to Sisyphus. Run 'sisyphus setup' to get started.");
|