sisyphi 1.1.8 → 1.1.10
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 +840 -165
- package/dist/cli.js.map +1 -1
- package/dist/templates/nvim-tutorial.txt +68 -0
- package/dist/templates/orchestrator-base.md +4 -2
- 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/dist/tui.js +479 -214
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
- package/templates/nvim-tutorial.txt +68 -0
- package/templates/orchestrator-base.md +4 -2
- 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";
|
|
@@ -820,15 +839,33 @@ function computeLastActivity(session) {
|
|
|
820
839
|
if (timestamps.length === 0) return null;
|
|
821
840
|
return new Date(Math.max(...timestamps));
|
|
822
841
|
}
|
|
823
|
-
function
|
|
842
|
+
function readRoadmap(cwd, sessionId) {
|
|
824
843
|
try {
|
|
825
|
-
|
|
826
|
-
return content.split("\n").filter((line) => /^\s*- \[ \]/.test(line)).map((line) => line.replace(/^\s*- \[ \]\s*/, "")).slice(0, 5);
|
|
844
|
+
return readFileSync3(roadmapPath(cwd, sessionId), "utf8");
|
|
827
845
|
} catch {
|
|
828
|
-
return
|
|
846
|
+
return null;
|
|
829
847
|
}
|
|
830
848
|
}
|
|
831
|
-
function
|
|
849
|
+
function readCycleLog(cwd, sessionId, cycle) {
|
|
850
|
+
try {
|
|
851
|
+
const path = cycleLogPath(cwd, sessionId, cycle);
|
|
852
|
+
if (!existsSync4(path)) return null;
|
|
853
|
+
return readFileSync3(path, "utf8");
|
|
854
|
+
} catch {
|
|
855
|
+
return null;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
function capturePaneOutput(paneId, lines = 50) {
|
|
859
|
+
try {
|
|
860
|
+
return execSync6(
|
|
861
|
+
`tmux capture-pane -t "${paneId}" -p -S -${lines}`,
|
|
862
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
863
|
+
).trimEnd();
|
|
864
|
+
} catch {
|
|
865
|
+
return null;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
function printSession(session, verbose) {
|
|
832
869
|
const status = colorize(session.status, session.status);
|
|
833
870
|
const sessionDuration = formatDuration(session.createdAt, session.completedAt);
|
|
834
871
|
console.log(`
|
|
@@ -836,7 +873,7 @@ ${BOLD}Session: ${session.id}${RESET}`);
|
|
|
836
873
|
console.log(` Status: ${status}`);
|
|
837
874
|
console.log(` Task: ${session.task}`);
|
|
838
875
|
if (session.context) {
|
|
839
|
-
const truncated = session.context.length > 120 ? session.context.slice(0, 120) + "..." : session.context;
|
|
876
|
+
const truncated = !verbose && session.context.length > 120 ? session.context.slice(0, 120) + "..." : session.context;
|
|
840
877
|
console.log(` Context: ${truncated}`);
|
|
841
878
|
}
|
|
842
879
|
console.log(` CWD: ${session.cwd}`);
|
|
@@ -857,15 +894,17 @@ ${BOLD}Active agents (${runningAgents.length}):${RESET}`);
|
|
|
857
894
|
const type = `${DIM}(${agent.agentType})${RESET}`;
|
|
858
895
|
const duration = formatDuration(agent.activeMs);
|
|
859
896
|
console.log(` ${agent.id} ${name} ${type} running ${duration}`);
|
|
897
|
+
if (verbose && agent.instruction) {
|
|
898
|
+
const truncated = agent.instruction.length > 200 ? agent.instruction.slice(0, 200) + "..." : agent.instruction;
|
|
899
|
+
console.log(` ${DIM}Instruction: ${truncated}${RESET}`);
|
|
900
|
+
}
|
|
860
901
|
}
|
|
861
902
|
}
|
|
862
|
-
const
|
|
863
|
-
if (
|
|
903
|
+
const roadmap = readRoadmap(session.cwd, session.id);
|
|
904
|
+
if (roadmap) {
|
|
864
905
|
console.log(`
|
|
865
|
-
${BOLD}
|
|
866
|
-
|
|
867
|
-
console.log(` - ${todo}`);
|
|
868
|
-
}
|
|
906
|
+
${BOLD}Roadmap:${RESET}`);
|
|
907
|
+
console.log(roadmap);
|
|
869
908
|
}
|
|
870
909
|
if (session.orchestratorCycles.length > 0) {
|
|
871
910
|
console.log(`
|
|
@@ -875,25 +914,68 @@ ${BOLD}Remaining (${todos.length} unchecked):${RESET}`);
|
|
|
875
914
|
const isLast = i === cycles.length - 1;
|
|
876
915
|
const phase = isLast && session.status === "active" ? inferOrchestratorPhase(session) : void 0;
|
|
877
916
|
console.log(formatCycle(cycles[i], phase));
|
|
917
|
+
if (verbose) {
|
|
918
|
+
const log = readCycleLog(session.cwd, session.id, cycles[i].cycle);
|
|
919
|
+
if (log) {
|
|
920
|
+
const lines = log.split("\n");
|
|
921
|
+
const preview = lines.slice(0, 20).join("\n");
|
|
922
|
+
console.log(` ${DIM}--- cycle log ---${RESET}`);
|
|
923
|
+
for (const line of preview.split("\n")) {
|
|
924
|
+
console.log(` ${DIM}${line}${RESET}`);
|
|
925
|
+
}
|
|
926
|
+
if (lines.length > 20) {
|
|
927
|
+
console.log(` ${DIM}... (${lines.length - 20} more lines)${RESET}`);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
878
931
|
}
|
|
879
932
|
}
|
|
880
933
|
if (session.agents.length > 0) {
|
|
881
934
|
console.log(`
|
|
882
935
|
${BOLD}Agents:${RESET}`);
|
|
883
936
|
for (const agent of session.agents) {
|
|
884
|
-
console.log(formatAgent(agent));
|
|
937
|
+
console.log(formatAgent(agent, verbose));
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (verbose) {
|
|
941
|
+
const lastCycle = session.orchestratorCycles[session.orchestratorCycles.length - 1];
|
|
942
|
+
if (lastCycle && !lastCycle.completedAt && lastCycle.paneId) {
|
|
943
|
+
const output = capturePaneOutput(lastCycle.paneId);
|
|
944
|
+
if (output) {
|
|
945
|
+
console.log(`
|
|
946
|
+
<orchestrator-pane-output lines="50">`);
|
|
947
|
+
console.log(output);
|
|
948
|
+
console.log(`</orchestrator-pane-output>`);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
for (const agent of runningAgents) {
|
|
952
|
+
if (agent.paneId) {
|
|
953
|
+
const output = capturePaneOutput(agent.paneId, 30);
|
|
954
|
+
if (output) {
|
|
955
|
+
console.log(`
|
|
956
|
+
<agent-pane-output agent="${agent.id}" name="${agent.name}" lines="30">`);
|
|
957
|
+
console.log(output);
|
|
958
|
+
console.log(`</agent-pane-output>`);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
885
961
|
}
|
|
886
962
|
}
|
|
963
|
+
if (verbose && session.completionReport) {
|
|
964
|
+
console.log(`
|
|
965
|
+
${BOLD}Completion Report:${RESET}`);
|
|
966
|
+
console.log(session.completionReport);
|
|
967
|
+
}
|
|
887
968
|
}
|
|
888
969
|
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) => {
|
|
970
|
+
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
971
|
const sessionId = sessionIdArg ?? process.env.SISYPHUS_SESSION_ID;
|
|
972
|
+
const verbose = opts?.verbose ?? false;
|
|
891
973
|
const request = { type: "status", sessionId };
|
|
892
974
|
const response = await sendRequest(request);
|
|
893
975
|
if (response.ok) {
|
|
894
976
|
const session = response.data?.session;
|
|
895
977
|
if (session) {
|
|
896
|
-
printSession(session);
|
|
978
|
+
printSession(session, verbose);
|
|
897
979
|
} else {
|
|
898
980
|
console.log("No session found");
|
|
899
981
|
}
|
|
@@ -1164,12 +1246,12 @@ function registerSetupKeybind(program2) {
|
|
|
1164
1246
|
}
|
|
1165
1247
|
|
|
1166
1248
|
// src/cli/commands/doctor.ts
|
|
1167
|
-
import { execSync as
|
|
1168
|
-
import { existsSync as
|
|
1249
|
+
import { execSync as execSync8 } from "child_process";
|
|
1250
|
+
import { existsSync as existsSync6, statSync } from "fs";
|
|
1169
1251
|
|
|
1170
1252
|
// src/cli/onboard.ts
|
|
1171
|
-
import { execSync as
|
|
1172
|
-
import { existsSync as
|
|
1253
|
+
import { execSync as execSync7 } from "child_process";
|
|
1254
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
1173
1255
|
import { homedir as homedir3 } from "os";
|
|
1174
1256
|
import { dirname as dirname2, join as join5 } from "path";
|
|
1175
1257
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1180,7 +1262,7 @@ function detectTerminal() {
|
|
|
1180
1262
|
}
|
|
1181
1263
|
function isTmuxAvailable() {
|
|
1182
1264
|
try {
|
|
1183
|
-
|
|
1265
|
+
execSync7("which tmux", { stdio: "pipe" });
|
|
1184
1266
|
return true;
|
|
1185
1267
|
} catch {
|
|
1186
1268
|
return false;
|
|
@@ -1188,7 +1270,7 @@ function isTmuxAvailable() {
|
|
|
1188
1270
|
}
|
|
1189
1271
|
function isBrewAvailable() {
|
|
1190
1272
|
try {
|
|
1191
|
-
|
|
1273
|
+
execSync7("which brew", { stdio: "pipe" });
|
|
1192
1274
|
return true;
|
|
1193
1275
|
} catch {
|
|
1194
1276
|
return false;
|
|
@@ -1198,7 +1280,7 @@ function tryAutoInstallTmux() {
|
|
|
1198
1280
|
if (!isBrewAvailable()) return false;
|
|
1199
1281
|
try {
|
|
1200
1282
|
console.log(" Installing tmux via Homebrew...");
|
|
1201
|
-
|
|
1283
|
+
execSync7("brew install tmux", { stdio: "inherit" });
|
|
1202
1284
|
return isTmuxAvailable();
|
|
1203
1285
|
} catch {
|
|
1204
1286
|
return false;
|
|
@@ -1209,11 +1291,11 @@ function checkItermOptionKey() {
|
|
|
1209
1291
|
return { checked: false, allCorrect: true, incorrectProfiles: [] };
|
|
1210
1292
|
}
|
|
1211
1293
|
const plistPath2 = join5(homedir3(), "Library", "Preferences", "com.googlecode.iterm2.plist");
|
|
1212
|
-
if (!
|
|
1294
|
+
if (!existsSync5(plistPath2)) {
|
|
1213
1295
|
return { checked: false, allCorrect: false, incorrectProfiles: [] };
|
|
1214
1296
|
}
|
|
1215
1297
|
try {
|
|
1216
|
-
const json =
|
|
1298
|
+
const json = execSync7(
|
|
1217
1299
|
`plutil -extract "New Bookmarks" json -o - "${plistPath2}"`,
|
|
1218
1300
|
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
1219
1301
|
);
|
|
@@ -1233,7 +1315,7 @@ function checkItermOptionKey() {
|
|
|
1233
1315
|
}
|
|
1234
1316
|
}
|
|
1235
1317
|
function hasExistingTmuxConf() {
|
|
1236
|
-
return
|
|
1318
|
+
return existsSync5(join5(homedir3(), ".tmux.conf")) || existsSync5(join5(homedir3(), ".config", "tmux", "tmux.conf"));
|
|
1237
1319
|
}
|
|
1238
1320
|
var TMUX_DEFAULTS = `# Sensible tmux defaults (installed by sisyphus)
|
|
1239
1321
|
# Customize freely \u2014 sisyphus won't overwrite this file.
|
|
@@ -1263,6 +1345,40 @@ set -g set-clipboard on
|
|
|
1263
1345
|
|
|
1264
1346
|
# Focus events (for editors)
|
|
1265
1347
|
set -g focus-events on
|
|
1348
|
+
|
|
1349
|
+
# --- Pane navigation (no prefix needed) ---
|
|
1350
|
+
bind -n C-h select-pane -L
|
|
1351
|
+
bind -n C-j select-pane -D
|
|
1352
|
+
bind -n C-k select-pane -U
|
|
1353
|
+
bind -n C-l select-pane -R
|
|
1354
|
+
|
|
1355
|
+
# --- Window navigation (no prefix needed) ---
|
|
1356
|
+
bind -n C-n next-window
|
|
1357
|
+
bind -n C-p previous-window
|
|
1358
|
+
|
|
1359
|
+
# --- New window / splits preserve cwd ---
|
|
1360
|
+
bind c new-window -c "#{pane_current_path}"
|
|
1361
|
+
bind '"' split-window -v -c "#{pane_current_path}"
|
|
1362
|
+
bind % split-window -h -c "#{pane_current_path}"
|
|
1363
|
+
|
|
1364
|
+
# --- Kill pane + rebalance ---
|
|
1365
|
+
bind x kill-pane \\; select-layout even-horizontal
|
|
1366
|
+
|
|
1367
|
+
# --- Auto-rebalance on pane close ---
|
|
1368
|
+
set-hook -g after-kill-pane "select-layout even-horizontal"
|
|
1369
|
+
set-hook -g pane-exited "select-layout even-horizontal"
|
|
1370
|
+
|
|
1371
|
+
# --- Manual re-tile ---
|
|
1372
|
+
bind = select-layout even-horizontal
|
|
1373
|
+
|
|
1374
|
+
# --- Scroll (no prefix needed) ---
|
|
1375
|
+
bind -n C-u copy-mode \\; send-keys -X halfpage-up
|
|
1376
|
+
bind -n C-d copy-mode \\; send-keys -X halfpage-down
|
|
1377
|
+
|
|
1378
|
+
# --- Vi copy mode ---
|
|
1379
|
+
setw -g mode-keys vi
|
|
1380
|
+
bind -T copy-mode-vi v send-keys -X begin-selection
|
|
1381
|
+
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
|
|
1266
1382
|
`;
|
|
1267
1383
|
function writeTmuxDefaults() {
|
|
1268
1384
|
const confPath = join5(homedir3(), ".tmux.conf");
|
|
@@ -1270,7 +1386,7 @@ function writeTmuxDefaults() {
|
|
|
1270
1386
|
}
|
|
1271
1387
|
function isNvimAvailable() {
|
|
1272
1388
|
try {
|
|
1273
|
-
|
|
1389
|
+
execSync7("which nvim", { stdio: "pipe" });
|
|
1274
1390
|
return true;
|
|
1275
1391
|
} catch {
|
|
1276
1392
|
return false;
|
|
@@ -1278,13 +1394,13 @@ function isNvimAvailable() {
|
|
|
1278
1394
|
}
|
|
1279
1395
|
function getNvimVersion() {
|
|
1280
1396
|
try {
|
|
1281
|
-
return
|
|
1397
|
+
return execSync7("nvim --version", { encoding: "utf-8", stdio: "pipe" }).split("\n")[0]?.replace("NVIM ", "") || "unknown";
|
|
1282
1398
|
} catch {
|
|
1283
1399
|
return "unknown";
|
|
1284
1400
|
}
|
|
1285
1401
|
}
|
|
1286
1402
|
function hasLazyVimConfig() {
|
|
1287
|
-
return
|
|
1403
|
+
return existsSync5(join5(homedir3(), ".config", "nvim", "lazy-lock.json"));
|
|
1288
1404
|
}
|
|
1289
1405
|
function tryAutoInstallNvim() {
|
|
1290
1406
|
if (isNvimAvailable()) {
|
|
@@ -1295,7 +1411,7 @@ function tryAutoInstallNvim() {
|
|
|
1295
1411
|
}
|
|
1296
1412
|
try {
|
|
1297
1413
|
console.log(" Installing neovim via Homebrew...");
|
|
1298
|
-
|
|
1414
|
+
execSync7("brew install neovim", { stdio: "inherit" });
|
|
1299
1415
|
} catch {
|
|
1300
1416
|
return { installed: false, autoInstalled: false, version: "", lazyVimInstalled: false };
|
|
1301
1417
|
}
|
|
@@ -1304,13 +1420,13 @@ function tryAutoInstallNvim() {
|
|
|
1304
1420
|
}
|
|
1305
1421
|
const nvimConfigDir = join5(homedir3(), ".config", "nvim");
|
|
1306
1422
|
let lazyVimInstalled = false;
|
|
1307
|
-
if (!
|
|
1423
|
+
if (!existsSync5(nvimConfigDir)) {
|
|
1308
1424
|
try {
|
|
1309
1425
|
console.log(" Cloning LazyVim starter config...");
|
|
1310
|
-
|
|
1426
|
+
execSync7(`git clone https://github.com/LazyVim/starter ${nvimConfigDir}`, { stdio: "inherit" });
|
|
1311
1427
|
const gitDir = join5(nvimConfigDir, ".git");
|
|
1312
|
-
if (
|
|
1313
|
-
|
|
1428
|
+
if (existsSync5(gitDir)) {
|
|
1429
|
+
execSync7(`rm -rf "${gitDir}"`, { stdio: "pipe" });
|
|
1314
1430
|
}
|
|
1315
1431
|
lazyVimInstalled = true;
|
|
1316
1432
|
} catch {
|
|
@@ -1326,15 +1442,15 @@ function bundledBeginCommandPath() {
|
|
|
1326
1442
|
return join5(distDir, "templates", "begin.md");
|
|
1327
1443
|
}
|
|
1328
1444
|
function isBeginCommandInstalled() {
|
|
1329
|
-
return
|
|
1445
|
+
return existsSync5(beginCommandPath());
|
|
1330
1446
|
}
|
|
1331
1447
|
function installBeginCommand() {
|
|
1332
1448
|
const dest = beginCommandPath();
|
|
1333
|
-
if (
|
|
1449
|
+
if (existsSync5(dest)) {
|
|
1334
1450
|
return { installed: true, autoInstalled: false, path: dest };
|
|
1335
1451
|
}
|
|
1336
1452
|
const src = bundledBeginCommandPath();
|
|
1337
|
-
if (!
|
|
1453
|
+
if (!existsSync5(src)) {
|
|
1338
1454
|
return { installed: false, autoInstalled: false, path: dest };
|
|
1339
1455
|
}
|
|
1340
1456
|
try {
|
|
@@ -1378,7 +1494,7 @@ function checkNodeVersion() {
|
|
|
1378
1494
|
}
|
|
1379
1495
|
function checkClaudeCli() {
|
|
1380
1496
|
try {
|
|
1381
|
-
|
|
1497
|
+
execSync8("which claude", { stdio: "pipe" });
|
|
1382
1498
|
return { name: "Claude CLI", status: "ok", detail: "Found on PATH" };
|
|
1383
1499
|
} catch {
|
|
1384
1500
|
return {
|
|
@@ -1391,7 +1507,7 @@ function checkClaudeCli() {
|
|
|
1391
1507
|
}
|
|
1392
1508
|
function checkGit() {
|
|
1393
1509
|
try {
|
|
1394
|
-
const version =
|
|
1510
|
+
const version = execSync8("git --version", { encoding: "utf-8", stdio: "pipe" }).trim();
|
|
1395
1511
|
return { name: "git", status: "ok", detail: version };
|
|
1396
1512
|
} catch {
|
|
1397
1513
|
return { name: "git", status: "fail", detail: "Not found on PATH", fix: "Install git: https://git-scm.com/downloads" };
|
|
@@ -1399,7 +1515,7 @@ function checkGit() {
|
|
|
1399
1515
|
}
|
|
1400
1516
|
function checkTmuxVersion() {
|
|
1401
1517
|
try {
|
|
1402
|
-
const version =
|
|
1518
|
+
const version = execSync8("tmux -V", { encoding: "utf-8", stdio: "pipe" }).trim();
|
|
1403
1519
|
const match = version.match(/(\d+\.\d+)/);
|
|
1404
1520
|
if (!match) return { name: "tmux version", status: "warn", detail: `Could not parse version: ${version}` };
|
|
1405
1521
|
const ver = parseFloat(match[1]);
|
|
@@ -1425,7 +1541,7 @@ function checkDaemonInstalled() {
|
|
|
1425
1541
|
};
|
|
1426
1542
|
}
|
|
1427
1543
|
const pid = daemonPidPath();
|
|
1428
|
-
if (
|
|
1544
|
+
if (existsSync6(pid)) {
|
|
1429
1545
|
return { name: "Daemon setup", status: "ok", detail: `PID file found at ${pid}` };
|
|
1430
1546
|
}
|
|
1431
1547
|
return {
|
|
@@ -1437,7 +1553,7 @@ function checkDaemonInstalled() {
|
|
|
1437
1553
|
}
|
|
1438
1554
|
function checkDaemonRunning() {
|
|
1439
1555
|
const pid = daemonPidPath();
|
|
1440
|
-
if (!
|
|
1556
|
+
if (!existsSync6(pid)) {
|
|
1441
1557
|
const fix = process.platform === "darwin" ? "launchctl load -w ~/Library/LaunchAgents/com.sisyphus.daemon.plist" : "sisyphusd & \u2014 or check if the process is running";
|
|
1442
1558
|
return {
|
|
1443
1559
|
name: "Daemon process",
|
|
@@ -1448,7 +1564,7 @@ function checkDaemonRunning() {
|
|
|
1448
1564
|
}
|
|
1449
1565
|
try {
|
|
1450
1566
|
const sock = socketPath();
|
|
1451
|
-
|
|
1567
|
+
execSync8(`test -S "${sock}"`, { stdio: "pipe" });
|
|
1452
1568
|
return { name: "Daemon process", status: "ok", detail: `Socket at ${sock}` };
|
|
1453
1569
|
} catch {
|
|
1454
1570
|
return {
|
|
@@ -1461,13 +1577,13 @@ function checkDaemonRunning() {
|
|
|
1461
1577
|
}
|
|
1462
1578
|
function checkTmux() {
|
|
1463
1579
|
try {
|
|
1464
|
-
|
|
1580
|
+
execSync8("which tmux", { stdio: "pipe" });
|
|
1465
1581
|
} catch {
|
|
1466
1582
|
const installHint = process.platform === "darwin" ? "brew install tmux" : "apt install tmux (Debian/Ubuntu) or your package manager";
|
|
1467
1583
|
return { name: "tmux", status: "fail", detail: "Not found on PATH", fix: installHint };
|
|
1468
1584
|
}
|
|
1469
1585
|
try {
|
|
1470
|
-
|
|
1586
|
+
execSync8("tmux list-sessions", { stdio: "pipe" });
|
|
1471
1587
|
return { name: "tmux", status: "ok", detail: "Running" };
|
|
1472
1588
|
} catch {
|
|
1473
1589
|
return { name: "tmux", status: "warn", detail: "Installed but no server running" };
|
|
@@ -1475,7 +1591,7 @@ function checkTmux() {
|
|
|
1475
1591
|
}
|
|
1476
1592
|
function checkCycleScript() {
|
|
1477
1593
|
const path = cycleScriptPath();
|
|
1478
|
-
if (!
|
|
1594
|
+
if (!existsSync6(path)) {
|
|
1479
1595
|
return {
|
|
1480
1596
|
name: "Cycle script",
|
|
1481
1597
|
status: "fail",
|
|
@@ -1500,7 +1616,7 @@ function checkCycleScript() {
|
|
|
1500
1616
|
function checkTmuxKeybind() {
|
|
1501
1617
|
const existing = getExistingBinding(DEFAULT_KEY);
|
|
1502
1618
|
if (existing === null) {
|
|
1503
|
-
if (
|
|
1619
|
+
if (existsSync6(sisyphusTmuxConfPath())) {
|
|
1504
1620
|
return {
|
|
1505
1621
|
name: `Tmux keybind (${DEFAULT_KEY})`,
|
|
1506
1622
|
status: "warn",
|
|
@@ -1526,7 +1642,7 @@ function checkTmuxKeybind() {
|
|
|
1526
1642
|
}
|
|
1527
1643
|
function checkGlobalDir() {
|
|
1528
1644
|
const dir = globalDir();
|
|
1529
|
-
if (
|
|
1645
|
+
if (existsSync6(dir)) {
|
|
1530
1646
|
return { name: "Data directory", status: "ok", detail: dir };
|
|
1531
1647
|
}
|
|
1532
1648
|
return { name: "Data directory", status: "warn", detail: `${dir} does not exist (created on first use)` };
|
|
@@ -1580,7 +1696,7 @@ function checkNvim() {
|
|
|
1580
1696
|
return { name: "nvim", status: "warn", detail: "Not installed", fix };
|
|
1581
1697
|
}
|
|
1582
1698
|
try {
|
|
1583
|
-
const version =
|
|
1699
|
+
const version = execSync8("nvim --version", { encoding: "utf-8", stdio: "pipe" }).split("\n")[0]?.replace("NVIM ", "");
|
|
1584
1700
|
return { name: "nvim", status: "ok", detail: version ?? "installed" };
|
|
1585
1701
|
} catch {
|
|
1586
1702
|
return { name: "nvim", status: "ok", detail: "installed" };
|
|
@@ -1634,6 +1750,12 @@ function registerCompanionContext(program2) {
|
|
|
1634
1750
|
}
|
|
1635
1751
|
|
|
1636
1752
|
// src/cli/commands/getting-started.ts
|
|
1753
|
+
import { execSync as execSync9 } from "child_process";
|
|
1754
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
1755
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1756
|
+
function templatePath(name) {
|
|
1757
|
+
return join6(dirname3(fileURLToPath3(import.meta.url)), "templates", name);
|
|
1758
|
+
}
|
|
1637
1759
|
function isClaudeCode() {
|
|
1638
1760
|
return !!process.env["CLAUDECODE"];
|
|
1639
1761
|
}
|
|
@@ -1678,7 +1800,7 @@ function printStep0() {
|
|
|
1678
1800
|
|
|
1679
1801
|
## Tutorial Overview
|
|
1680
1802
|
|
|
1681
|
-
This tutorial has
|
|
1803
|
+
This tutorial has 6 steps. Share this overview so the user knows what's coming and can skip ahead:
|
|
1682
1804
|
|
|
1683
1805
|
| Step | Topic | Command |
|
|
1684
1806
|
|------|-------|---------|
|
|
@@ -1687,6 +1809,7 @@ This tutorial has 5 steps. Share this overview so the user knows what's coming a
|
|
|
1687
1809
|
| 2 | Nvim basics \u2014 open, save, quit (optional) | \`--tutorial 2\` |
|
|
1688
1810
|
| 3 | Sisyphus concepts \u2014 session model & keybinds | \`--tutorial 3\` |
|
|
1689
1811
|
| 4 | Live demo \u2014 launch and observe a real session | \`--tutorial 4\` |
|
|
1812
|
+
| 5 | What's next \u2014 real usage guidance & suggestions | \`--tutorial 5\` |
|
|
1690
1813
|
|
|
1691
1814
|
Tell the user they can skip to any step with \`sisyphus getting-started --tutorial <N>\`.
|
|
1692
1815
|
|
|
@@ -1776,9 +1899,12 @@ tmux split-window -h
|
|
|
1776
1899
|
Tell them: "I just split your terminal. You should see two panes side by side."
|
|
1777
1900
|
|
|
1778
1901
|
Explain navigation:
|
|
1779
|
-
- \`Ctrl
|
|
1780
|
-
- \`Ctrl
|
|
1781
|
-
-
|
|
1902
|
+
- \`Ctrl+l\`: move to the right pane
|
|
1903
|
+
- \`Ctrl+h\`: move to the left pane
|
|
1904
|
+
- \`Ctrl+j\`: move to the pane below
|
|
1905
|
+
- \`Ctrl+k\`: move to the pane above
|
|
1906
|
+
- No prefix key needed \u2014 just hold Ctrl and press the direction letter
|
|
1907
|
+
- For windows: \`Ctrl+n\` next window, \`Ctrl+p\` previous window
|
|
1782
1908
|
|
|
1783
1909
|
Ask them to try navigating between panes.
|
|
1784
1910
|
|
|
@@ -1795,11 +1921,14 @@ Or tell them they can type \`exit\` in the extra pane to close it.
|
|
|
1795
1921
|
|
|
1796
1922
|
- **Detach**: \`Ctrl-b d\` \u2014 leaves tmux running in background, returns to normal terminal
|
|
1797
1923
|
- **Reattach**: \`tmux attach\` (or \`tmux a\`) \u2014 reconnects to the running session
|
|
1798
|
-
- **Scroll
|
|
1924
|
+
- **Scroll up/down**: \`Ctrl+u\` / \`Ctrl+d\` \u2014 scroll half-page up/down (no prefix needed). Press \`q\` to exit scroll mode.
|
|
1925
|
+
- **New window**: \`Ctrl-b n\` \u2014 opens a new window in the current directory
|
|
1926
|
+
- **Kill pane**: \`Ctrl-b x\` \u2014 closes the current pane and rebalances layout
|
|
1927
|
+
- **Re-tile**: \`Ctrl-b =\` \u2014 rebalance all panes to equal widths
|
|
1799
1928
|
|
|
1800
1929
|
### 5. Verification
|
|
1801
1930
|
|
|
1802
|
-
Ask the user to confirm: "Can you navigate between panes with Ctrl
|
|
1931
|
+
Ask the user to confirm: "Can you navigate between panes with Ctrl+h and Ctrl+l?"
|
|
1803
1932
|
|
|
1804
1933
|
Once confirmed, proceed:
|
|
1805
1934
|
\`\`\`
|
|
@@ -1819,40 +1948,39 @@ function printStep2() {
|
|
|
1819
1948
|
|
|
1820
1949
|
## Instructions for Claude
|
|
1821
1950
|
|
|
1822
|
-
This step is OPTIONAL. Nvim is useful for reviewing
|
|
1951
|
+
This step is OPTIONAL. Nvim is useful for reviewing and editing files when you jump into agent panes, but not required.
|
|
1952
|
+
|
|
1953
|
+
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
1954
|
|
|
1824
1955
|
### If nvim is NOT installed (nvimInstalled: false)
|
|
1825
1956
|
|
|
1826
|
-
Ask the user: "Neovim is handy for reviewing files in tmux panes. Want me to install it, or skip this step?"
|
|
1957
|
+
Ask the user: "Neovim is handy for reviewing and editing files in tmux panes. Want me to install it, or skip this step?"
|
|
1827
1958
|
|
|
1828
1959
|
- **Install**: Run \`brew install neovim\` (macOS) or suggest their package manager
|
|
1829
1960
|
- **Skip**: That's fine \u2014 they can use \`cat\`, \`less\`, or any editor they prefer. Proceed to step 3.
|
|
1830
1961
|
|
|
1831
1962
|
### If nvim IS installed (nvimInstalled: true)
|
|
1832
1963
|
|
|
1833
|
-
|
|
1964
|
+
Briefly explain the key concept \u2014 nvim has two modes:
|
|
1834
1965
|
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
3. **Quit without saving**: \`:q!\` (colon, q, exclamation mark, Enter)
|
|
1966
|
+
- **Normal mode** (default): Keys are commands, not text. This is where you navigate.
|
|
1967
|
+
- **Insert mode**: Press \`i\` to enter. Now you type normally. \`Esc\` goes back to normal.
|
|
1838
1968
|
|
|
1839
|
-
|
|
1969
|
+
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
1970
|
|
|
1841
|
-
|
|
1971
|
+
Open the bundled tutorial file in a split pane:
|
|
1842
1972
|
\`\`\`
|
|
1843
|
-
|
|
1973
|
+
cp ${templatePath("nvim-tutorial.txt")} /tmp/sisyphus-nvim-tutorial.txt
|
|
1974
|
+
tmux split-window -h "nvim /tmp/sisyphus-nvim-tutorial.txt"
|
|
1844
1975
|
\`\`\`
|
|
1845
1976
|
|
|
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\`
|
|
1977
|
+
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
1978
|
|
|
1851
|
-
Tell them: "
|
|
1979
|
+
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
1980
|
|
|
1853
1981
|
### Verification
|
|
1854
1982
|
|
|
1855
|
-
Ask if they were able to
|
|
1983
|
+
Ask if they were able to edit and save the file (or if they skipped).
|
|
1856
1984
|
|
|
1857
1985
|
Proceed:
|
|
1858
1986
|
\`\`\`
|
|
@@ -1862,13 +1990,75 @@ sisyphus getting-started --tutorial 3
|
|
|
1862
1990
|
`);
|
|
1863
1991
|
}
|
|
1864
1992
|
function printStep3() {
|
|
1993
|
+
let rightOptionKeyStatus = "unknown";
|
|
1994
|
+
const terminal = detectTerminal();
|
|
1995
|
+
if (!terminal.isIterm) {
|
|
1996
|
+
rightOptionKeyStatus = "not-iterm";
|
|
1997
|
+
} else {
|
|
1998
|
+
const result = checkItermOptionKey();
|
|
1999
|
+
if (!result.checked) {
|
|
2000
|
+
rightOptionKeyStatus = "could-not-check";
|
|
2001
|
+
} else if (result.allCorrect) {
|
|
2002
|
+
rightOptionKeyStatus = "ok";
|
|
2003
|
+
} else {
|
|
2004
|
+
rightOptionKeyStatus = `incorrect:${result.incorrectProfiles.join(",")}`;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
1865
2007
|
console.log(`
|
|
1866
2008
|
<claude-instructions>
|
|
1867
2009
|
# Sisyphus Getting Started \u2014 Step 3: Sisyphus Concepts & Keybinds
|
|
1868
2010
|
|
|
2011
|
+
## Environment Data
|
|
2012
|
+
- rightOptionKeyStatus: ${rightOptionKeyStatus}
|
|
2013
|
+
|
|
1869
2014
|
## Instructions for Claude
|
|
1870
2015
|
|
|
1871
|
-
### 1.
|
|
2016
|
+
### 1. CRITICAL FIRST: Right Option Key Setup
|
|
2017
|
+
|
|
2018
|
+
**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.
|
|
2019
|
+
|
|
2020
|
+
**Check the environment data above:**
|
|
2021
|
+
|
|
2022
|
+
- **rightOptionKeyStatus: ok** \u2014 They're all set, briefly confirm and move on.
|
|
2023
|
+
|
|
2024
|
+
- **rightOptionKeyStatus: incorrect:ProfileName** \u2014 Walk them through the fix:
|
|
2025
|
+
|
|
2026
|
+
> Your Right Option key isn't configured correctly yet. Here's how to fix it:
|
|
2027
|
+
>
|
|
2028
|
+
> 1. Open **iTerm2 Settings** (Cmd+,)
|
|
2029
|
+
> 2. Go to **Profiles** \u2192 select your profile (shown above)
|
|
2030
|
+
> 3. Click the **Keys** tab
|
|
2031
|
+
> 4. At the bottom, find **Right Option Key**
|
|
2032
|
+
> 5. Change it from **Normal** to **Esc+**
|
|
2033
|
+
>
|
|
2034
|
+
> \`\`\`
|
|
2035
|
+
> \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
|
|
2036
|
+
> \u2502 Profiles > Keys \u2502
|
|
2037
|
+
> \u2502 \u2502
|
|
2038
|
+
> \u2502 Right Option Key: \u2502
|
|
2039
|
+
> \u2502 \u25CB Normal (sends special chars like \xDF) \u2502
|
|
2040
|
+
> \u2502 \u25CF Esc+ (sends escape sequences) \u2190 \u2713 \u2502
|
|
2041
|
+
> \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
|
|
2042
|
+
> \`\`\`
|
|
2043
|
+
>
|
|
2044
|
+
> **Why right and not left?** You'll still want the left Option key for
|
|
2045
|
+
> typing special characters (accents, symbols). The right Option key
|
|
2046
|
+
> becomes your "Meta" key for tmux/sisyphus keybinds.
|
|
2047
|
+
|
|
2048
|
+
After they change it, have them verify by re-running \`sisyphus doctor\` \u2014 look for "Right Option Key: Esc+".
|
|
2049
|
+
|
|
2050
|
+
- **rightOptionKeyStatus: not-iterm** \u2014 They're not using iTerm2. Explain:
|
|
2051
|
+
> Sisyphus keybinds use Option as Meta. In iTerm2 this is configured via
|
|
2052
|
+
> "Right Option Key \u2192 Esc+". For your terminal, look for a similar setting
|
|
2053
|
+
> like "Option sends Meta" or "Option sends Esc+". Without this, pressing
|
|
2054
|
+
> Option+s will type a special character instead of triggering the keybind.
|
|
2055
|
+
|
|
2056
|
+
- **rightOptionKeyStatus: could-not-check** or **unknown** \u2014 Ask them to manually check:
|
|
2057
|
+
> Press Option+s in your terminal. If you see \`\xDF\` (or another special character),
|
|
2058
|
+
> your Option key needs to be reconfigured. In iTerm2: Settings \u2192 Profiles \u2192 Keys \u2192
|
|
2059
|
+
> Right Option Key \u2192 Esc+.
|
|
2060
|
+
|
|
2061
|
+
### 2. Explain the session model
|
|
1872
2062
|
|
|
1873
2063
|
This is the KEY concept. Use the diagram and be clear:
|
|
1874
2064
|
|
|
@@ -1876,7 +2066,7 @@ This is the KEY concept. Use the diagram and be clear:
|
|
|
1876
2066
|
YOUR tmux session ("work") Sisyphus tmux session ("sisyphus-abc123")
|
|
1877
2067
|
\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
2068
|
\u2502 \u2502 \u2502 Orch \u2502 Agent \u2502 Agent \u2502
|
|
1879
|
-
\u2502 Your normal work \u2502 \u2190\u2500\u2500\u2192
|
|
2069
|
+
\u2502 Your normal work \u2502 \u2190\u2500\u2500\u2192 \u2502 (yellow)\u2502 (blue) \u2502 (green) \u2502
|
|
1880
2070
|
\u2502 + dashboard \u2502 \u2502 \u2502 \u2502 \u2502
|
|
1881
2071
|
\u2502 \u2502 \u2502 Plans & \u2502 Writes \u2502 Writes \u2502
|
|
1882
2072
|
\u2502 \u2502 \u2502 assigns \u2502 code \u2502 tests \u2502
|
|
@@ -1890,40 +2080,36 @@ Key points:
|
|
|
1890
2080
|
- Your session stays clean \u2014 you get a **dashboard** for monitoring
|
|
1891
2081
|
- You can jump between your session and the sisyphus session to observe
|
|
1892
2082
|
|
|
1893
|
-
###
|
|
2083
|
+
### 3. Teach keybinds
|
|
1894
2084
|
|
|
1895
|
-
Two keybinds to remember:
|
|
2085
|
+
Two keybinds to remember (both use the RIGHT Option key):
|
|
1896
2086
|
|
|
1897
2087
|
| Keybind | Action |
|
|
1898
2088
|
|---------|--------|
|
|
1899
|
-
|
|
|
1900
|
-
|
|
|
1901
|
-
|
|
1902
|
-
"M" means "Meta" which is the Option key on macOS. So \`M-s\` = hold Option, press s.
|
|
2089
|
+
| Right Option + s | Cycle through sisyphus sessions |
|
|
2090
|
+
| Right Option + Shift + s | Jump back to dashboard |
|
|
1903
2091
|
|
|
1904
|
-
###
|
|
2092
|
+
### 4. Verify keybinds are installed
|
|
1905
2093
|
|
|
1906
2094
|
Run \`sisyphus doctor\` and check the output. Look for:
|
|
1907
2095
|
- "Cycle script" \u2014 should be \u2713
|
|
1908
2096
|
- "Tmux keybind" \u2014 should be \u2713
|
|
2097
|
+
- "Right Option Key" \u2014 should be "Esc+"
|
|
1909
2098
|
|
|
1910
|
-
If
|
|
2099
|
+
If cycle script or keybind is missing, run: \`sisyphus setup-keybind\`
|
|
1911
2100
|
|
|
1912
|
-
###
|
|
2101
|
+
### 5. Test the keybind
|
|
1913
2102
|
|
|
1914
|
-
Have the user try pressing
|
|
2103
|
+
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
2104
|
|
|
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
|
|
2105
|
+
If they see \`\xDF\` or similar, circle back to the Right Option Key setup above.
|
|
1920
2106
|
|
|
1921
|
-
###
|
|
2107
|
+
### 6. Verification
|
|
1922
2108
|
|
|
1923
2109
|
Confirm:
|
|
1924
2110
|
- 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
|
|
2111
|
+
- \`sisyphus doctor\` shows keybinds installed AND Right Option Key: Esc+
|
|
2112
|
+
- Right Option + s doesn't produce a special character
|
|
1927
2113
|
|
|
1928
2114
|
Proceed:
|
|
1929
2115
|
\`\`\`
|
|
@@ -1946,72 +2132,561 @@ This is the grand finale \u2014 a live demo session.
|
|
|
1946
2132
|
Run \`sisyphus doctor\` first. If any checks are failing, help the user fix them before proceeding.
|
|
1947
2133
|
All core checks (tmux, daemon, keybinds) should be \u2713.
|
|
1948
2134
|
|
|
1949
|
-
### 2.
|
|
2135
|
+
### 2. BEFORE launching: Teach navigation
|
|
2136
|
+
|
|
2137
|
+
**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:
|
|
1950
2138
|
|
|
1951
|
-
|
|
2139
|
+
Explain clearly:
|
|
2140
|
+
|
|
2141
|
+
> 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:
|
|
2142
|
+
>
|
|
2143
|
+
> \`\`\`
|
|
2144
|
+
> Window 1 (you are here) Window 2 (dashboard)
|
|
2145
|
+
> \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
|
|
2146
|
+
> \u2502 Claude Code \u2502 \u2502 Sisyphus \u2502
|
|
2147
|
+
> \u2502 (this session) \u2502 \u2192 \u2502 Dashboard \u2502
|
|
2148
|
+
> \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
|
|
2149
|
+
> Ctrl+n \u2192 \u2190 Ctrl+p
|
|
2150
|
+
> \`\`\`
|
|
2151
|
+
>
|
|
2152
|
+
> - **\`Ctrl+n\`** \u2014 next window (go to dashboard)
|
|
2153
|
+
> - **\`Ctrl+p\`** \u2014 previous window (come back here)
|
|
2154
|
+
>
|
|
2155
|
+
> And remember from step 3:
|
|
2156
|
+
> - **Right Option + s** \u2014 jump to the sisyphus agent session (where you can watch agents work live)
|
|
2157
|
+
> - **Right Option + Shift + s** \u2014 jump back to dashboard
|
|
2158
|
+
|
|
2159
|
+
Have the user confirm they understand these keybinds before proceeding.
|
|
2160
|
+
|
|
2161
|
+
### 3. Set expectations, copy demo app, and launch
|
|
2162
|
+
|
|
2163
|
+
First, copy the demo todo app to a temp directory and init a git repo (sisyphus needs git):
|
|
1952
2164
|
\`\`\`
|
|
1953
|
-
|
|
2165
|
+
rm -rf /tmp/sisyphus-tutorial-demo
|
|
2166
|
+
cp -r ${templatePath("tutorial-demo")} /tmp/sisyphus-tutorial-demo
|
|
2167
|
+
git -C /tmp/sisyphus-tutorial-demo init
|
|
2168
|
+
git -C /tmp/sisyphus-tutorial-demo add -A
|
|
2169
|
+
git -C /tmp/sisyphus-tutorial-demo commit -m "Initial todo app"
|
|
1954
2170
|
\`\`\`
|
|
1955
2171
|
|
|
1956
|
-
|
|
2172
|
+
Tell the user:
|
|
1957
2173
|
|
|
1958
|
-
|
|
2174
|
+
> I've set up a small todo app in /tmp/sisyphus-tutorial-demo \u2014 a Node.js API
|
|
2175
|
+
> with a few files. I'm going to launch sisyphus on it. Here's what will happen:
|
|
2176
|
+
> 1. The dashboard opens automatically (you'll be switched to it)
|
|
2177
|
+
> 2. Press **Ctrl+p** to come back here to Claude \u2014 I'll guide you through what to watch
|
|
2178
|
+
> 3. The session takes a few minutes. You can watch agents work live!
|
|
1959
2179
|
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
-
|
|
1963
|
-
|
|
2180
|
+
Then launch from the demo directory:
|
|
2181
|
+
\`\`\`
|
|
2182
|
+
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."
|
|
2183
|
+
\`\`\`
|
|
1964
2184
|
|
|
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"
|
|
2185
|
+
After launching, tell them:
|
|
1969
2186
|
|
|
1970
|
-
**
|
|
1971
|
-
- Press \`M-S\` (Option+Shift+s) to jump back to the dashboard
|
|
1972
|
-
- Or \`M-s\` to cycle through
|
|
2187
|
+
> 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.
|
|
1973
2188
|
|
|
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
|
|
2189
|
+
Wait for them to confirm they're back, then start live commentary.
|
|
1979
2190
|
|
|
1980
|
-
### 4.
|
|
2191
|
+
### 4. Live commentary loop
|
|
2192
|
+
|
|
2193
|
+
**This is the most important part of the demo.** Don't just launch and wait \u2014 actively narrate.
|
|
2194
|
+
|
|
2195
|
+
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.
|
|
2196
|
+
|
|
2197
|
+
**How to narrate each phase:**
|
|
2198
|
+
|
|
2199
|
+
- **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."
|
|
2200
|
+
|
|
2201
|
+
- **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."
|
|
2202
|
+
|
|
2203
|
+
- **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\`)."
|
|
2204
|
+
|
|
2205
|
+
- **Agents submitting**: "Agent-001 just submitted its report! [N] more to go. When all agents finish, the orchestrator will respawn to review."
|
|
2206
|
+
|
|
2207
|
+
- **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."
|
|
2208
|
+
|
|
2209
|
+
- **Completion**: "The session is complete! Let me show you the results."
|
|
2210
|
+
|
|
2211
|
+
**Important:**
|
|
2212
|
+
- Keep commentary to 1-3 sentences per check \u2014 don't wall-of-text
|
|
2213
|
+
- Remind them of navigation keys when relevant ("jump over with Right Option + s to see this live")
|
|
2214
|
+
- If agents are still working with no change, say so briefly ("Still working... Agent-001 is the furthest along")
|
|
2215
|
+
- Reference specific agent names and tasks from the status output
|
|
2216
|
+
- Stop polling when status shows "completed"
|
|
2217
|
+
|
|
2218
|
+
Between polls, encourage the user to explore:
|
|
2219
|
+
> "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."
|
|
2220
|
+
|
|
2221
|
+
### 5. After completion
|
|
1981
2222
|
|
|
1982
2223
|
Once the session shows "completed":
|
|
1983
2224
|
|
|
1984
|
-
-
|
|
1985
|
-
-
|
|
1986
|
-
-
|
|
2225
|
+
- Show them what the agents built: \`cd /tmp/sisyphus-tutorial-demo && git log --oneline\`
|
|
2226
|
+
- Run the tests to prove the work: \`cd /tmp/sisyphus-tutorial-demo && node --test test.js\`
|
|
2227
|
+
- Show the session artifacts: find the session dir in \`.sisyphus/sessions/\` and show \`roadmap.md\`
|
|
2228
|
+
- Explain: "Every session creates a roadmap, agent reports, and logs \u2014 all stored in .sisyphus/sessions/"
|
|
2229
|
+
|
|
2230
|
+
### 6. Proceed to wrap-up
|
|
2231
|
+
|
|
2232
|
+
Tell the user the demo is done. Then run:
|
|
2233
|
+
\`\`\`
|
|
2234
|
+
sisyphus getting-started --tutorial 5
|
|
2235
|
+
\`\`\`
|
|
2236
|
+
</claude-instructions>
|
|
2237
|
+
`);
|
|
2238
|
+
}
|
|
2239
|
+
function printStep5() {
|
|
2240
|
+
let recentCommits = "";
|
|
2241
|
+
let topLevelFiles = "";
|
|
2242
|
+
try {
|
|
2243
|
+
recentCommits = execSync9("git log --oneline -15 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
2244
|
+
} catch {
|
|
2245
|
+
}
|
|
2246
|
+
try {
|
|
2247
|
+
topLevelFiles = execSync9("ls -1 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
2248
|
+
} catch {
|
|
2249
|
+
}
|
|
2250
|
+
console.log(`
|
|
2251
|
+
<claude-instructions>
|
|
2252
|
+
# Sisyphus Getting Started \u2014 Step 5: What's Next
|
|
2253
|
+
|
|
2254
|
+
## Codebase Context
|
|
2255
|
+
<recent-commits>
|
|
2256
|
+
${recentCommits || "(no git repo detected)"}
|
|
2257
|
+
</recent-commits>
|
|
1987
2258
|
|
|
1988
|
-
|
|
2259
|
+
<top-level-files>
|
|
2260
|
+
${topLevelFiles || "(could not list)"}
|
|
2261
|
+
</top-level-files>
|
|
1989
2262
|
|
|
1990
|
-
|
|
2263
|
+
## Instructions for Claude
|
|
1991
2264
|
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2265
|
+
### 1. Congratulate them
|
|
2266
|
+
|
|
2267
|
+
Tell them they've completed the tutorial and recap what they learned:
|
|
2268
|
+
- tmux basics (sessions, panes, navigation)
|
|
2269
|
+
- nvim basics for reviewing files
|
|
2270
|
+
- The sisyphus session model (separate tmux session for orchestrator + agents)
|
|
2271
|
+
- Monitoring with dashboard and keybinds
|
|
2272
|
+
- A live session lifecycle
|
|
2273
|
+
|
|
2274
|
+
### 2. Navigation cheat sheet
|
|
2275
|
+
|
|
2276
|
+
| Key | Action |
|
|
2277
|
+
|-----|--------|
|
|
2278
|
+
| \`Ctrl+n\` / \`Ctrl+p\` | Next/previous tmux window |
|
|
2279
|
+
| \`Ctrl+h/j/k/l\` | Navigate between panes |
|
|
2280
|
+
| \`Right Option + s\` | Jump to sisyphus agent session |
|
|
2281
|
+
| \`Right Option + Shift + s\` | Jump to dashboard |
|
|
2282
|
+
|
|
2283
|
+
### 3. How to use sisyphus for REAL work
|
|
2284
|
+
|
|
2285
|
+
This is the most important part. Explain clearly:
|
|
2286
|
+
|
|
2287
|
+
> **Sisyphus is for big, end-to-end features \u2014 the kind that need exploration,
|
|
2288
|
+
> planning, and parallel implementation across multiple systems.**
|
|
2000
2289
|
>
|
|
2001
|
-
>
|
|
2002
|
-
>
|
|
2003
|
-
|
|
2004
|
-
|
|
2290
|
+
> You don't need to define the task precisely. Broad is fine \u2014 the orchestrator
|
|
2291
|
+
> will explore the codebase, write specs, plan phases, and break it down itself.
|
|
2292
|
+
|
|
2293
|
+
**Real sisyphus sessions (from production use):**
|
|
2294
|
+
- "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
|
|
2295
|
+
- "Build multi-user organization features \u2014 invites, privilege gating, org switcher, workspace sharing, credit tracking" \u2014 touched auth, DB, API, UI, billing, permissions
|
|
2296
|
+
- "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
|
|
2297
|
+
- "Autonomous failure detection system across 8 sequential phases" \u2014 monitoring, alerting, recovery, dashboard, with each phase building on the last
|
|
2298
|
+
- "Comprehensive code quality audit \u2014 find and fix dead code, null handling, useless fallbacks" \u2014 systematic codebase-wide analysis and cleanup
|
|
2299
|
+
- "Implement @requirements.md" \u2014 point it at a spec and let it go
|
|
2300
|
+
|
|
2301
|
+
**NOT good for sisyphus:**
|
|
2302
|
+
- 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
|
|
2303
|
+
- 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.
|
|
2304
|
+
- Quick fixes, bug fixes, small refactors \u2014 use regular Claude Code
|
|
2305
|
+
|
|
2306
|
+
**How to start:**
|
|
2307
|
+
The easiest way is the \`/sisyphus:begin\` slash command inside Claude Code. Just tell Claude
|
|
2308
|
+
what you want to build and it'll hand it off to sisyphus with the right context.
|
|
2309
|
+
|
|
2310
|
+
Or directly: \`sisyphus start "your task" -c "any background context"\`
|
|
2311
|
+
|
|
2312
|
+
### 4. Suggest real tasks for THEIR codebase
|
|
2313
|
+
|
|
2314
|
+
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.
|
|
2315
|
+
|
|
2316
|
+
If there are no commits or files (e.g., they ran this from /tmp), skip this section.
|
|
2317
|
+
|
|
2318
|
+
Format as:
|
|
2319
|
+
> Based on your codebase, here are some tasks sisyphus would be great for:
|
|
2320
|
+
> - "..."
|
|
2321
|
+
> - "..."
|
|
2322
|
+
|
|
2323
|
+
### 5. There's more to learn
|
|
2324
|
+
|
|
2325
|
+
Tell them:
|
|
2326
|
+
|
|
2327
|
+
> There's actually a lot of depth to how sisyphus works \u2014 the design is intentional
|
|
2328
|
+
> and there's real reasoning behind why it does things the way it does. If you want
|
|
2329
|
+
> to understand the philosophy, or you want a deeper rundown on the dashboard,
|
|
2330
|
+
> monitoring, configuration, or how to steer sessions \u2014 just ask and I'll explain.
|
|
2331
|
+
|
|
2332
|
+
If the user says yes or asks to learn more, run \`sisyphus getting-started --explain\`
|
|
2333
|
+
and use its output to explain the system to them conversationally. Don't dump the whole
|
|
2334
|
+
thing \u2014 answer what they're curious about, using the reference as your source material.
|
|
2335
|
+
</claude-instructions>
|
|
2336
|
+
`);
|
|
2337
|
+
}
|
|
2338
|
+
function printExplain() {
|
|
2339
|
+
console.log(`
|
|
2340
|
+
<claude-instructions>
|
|
2341
|
+
# Sisyphus \u2014 Comprehensive Reference
|
|
2342
|
+
|
|
2343
|
+
This is a detailed reference for how sisyphus works. The user asked to understand
|
|
2344
|
+
sisyphus more deeply. Use this to answer their questions conversationally \u2014 don't dump
|
|
2345
|
+
the whole thing. Read through it, then respond to what they're curious about.
|
|
2346
|
+
|
|
2347
|
+
## Design Philosophy
|
|
2348
|
+
|
|
2349
|
+
Sisyphus is built on specific insights about how to get the best work out of LLM agents.
|
|
2350
|
+
These aren't arbitrary \u2014 each design decision solves a real failure mode.
|
|
2351
|
+
|
|
2352
|
+
### 1. The Orchestrator as "Human-in-the-Loop"
|
|
2353
|
+
|
|
2354
|
+
When you use Claude Code effectively, YOU are the orchestrator \u2014 you review work,
|
|
2355
|
+
steer direction, break problems down, and assign the next piece. Sisyphus automates
|
|
2356
|
+
that human role. The orchestrator does what a skilled developer does when prompting
|
|
2357
|
+
Claude: explore the codebase, understand the problem, write specs, plan phases,
|
|
2358
|
+
assign focused work, review results, and iterate.
|
|
2359
|
+
|
|
2360
|
+
The strategy layer mirrors how developers actually work on end-to-end features:
|
|
2361
|
+
explore, understand, spec, plan, implement, review, validate. The orchestrator
|
|
2362
|
+
follows this same workflow, but runs it with parallel agents.
|
|
2363
|
+
|
|
2364
|
+
### 2. Fresh Context Kills Shortcuts
|
|
2365
|
+
|
|
2366
|
+
The orchestrator is KILLED after every cycle and respawned fresh. This is the most
|
|
2367
|
+
important design decision.
|
|
2368
|
+
|
|
2369
|
+
When an LLM accumulates context over a long session, it starts taking shortcuts.
|
|
2370
|
+
It "knows" what it did earlier, so it skips re-reading, assumes things still hold,
|
|
2371
|
+
and builds on stale understanding. A fresh start forces honest reassessment every
|
|
2372
|
+
cycle \u2014 the orchestrator reads the actual state, not its memory of it.
|
|
2373
|
+
|
|
2374
|
+
This is inspired by adversarial training (think GANs) \u2014 better results come from
|
|
2375
|
+
adversarial pressure. Each fresh orchestrator effectively audits the previous cycle's
|
|
2376
|
+
work because it has no stake in defending prior decisions. It sees the roadmap, the
|
|
2377
|
+
reports, the code \u2014 and judges them with fresh eyes.
|
|
2378
|
+
|
|
2379
|
+
### 3. Single-Focus Agents
|
|
2380
|
+
|
|
2381
|
+
Each agent gets ONE task with a fully self-contained instruction. No context switching,
|
|
2382
|
+
no juggling multiple concerns, no "also while you're there could you..."
|
|
2383
|
+
|
|
2384
|
+
LLMs perform dramatically better when focused. An agent implementing a priority field
|
|
2385
|
+
doesn't think about the stats endpoint. It reads the relevant context, does its one
|
|
2386
|
+
thing well, and reports back. The orchestrator handles decomposition \u2014 agents handle
|
|
2387
|
+
execution.
|
|
2388
|
+
|
|
2389
|
+
### 4. Shared Context Directory (Saved Research)
|
|
2390
|
+
|
|
2391
|
+
Every session has a context/ directory where agents save research, specs, plans, and
|
|
2392
|
+
design docs. These files persist across ALL cycles and are visible to the orchestrator
|
|
2393
|
+
and subsequent agents.
|
|
2394
|
+
|
|
2395
|
+
This means research is never repeated. Cycle 1 agents explore and write findings to
|
|
2396
|
+
context/explore-auth-system.md. Cycle 3 agents read those findings and build on them.
|
|
2397
|
+
Knowledge accumulates even though the orchestrator itself is stateless.
|
|
2398
|
+
|
|
2399
|
+
### 5. Two-Layer Planning (Strategy + Roadmap)
|
|
2400
|
+
|
|
2401
|
+
The system maintains two documents at different abstraction levels:
|
|
2402
|
+
|
|
2403
|
+
**strategy.md** \u2014 The high-level problem-solving map. What phases exist, what gates
|
|
2404
|
+
between them, what backtrack paths exist. Updated every few cycles when the shape of
|
|
2405
|
+
work changes. Helps the orchestrator see the forest.
|
|
2406
|
+
|
|
2407
|
+
**roadmap.md** \u2014 Working memory. Updated every cycle. Current Stage, Exit Criteria,
|
|
2408
|
+
Active Context, Next Steps. The orchestrator reads this first each cycle to understand
|
|
2409
|
+
where things stand. Helps the orchestrator see the trees.
|
|
2410
|
+
|
|
2411
|
+
This prevents the failure mode where a single document becomes either too abstract
|
|
2412
|
+
to act on or too detailed to show the big picture.
|
|
2413
|
+
|
|
2414
|
+
### 6. Adversarial Review Is Built In
|
|
2415
|
+
|
|
2416
|
+
The orchestrator doesn't just implement \u2014 it runs mandatory critique cycles. After
|
|
2417
|
+
implementation, review agents attack different dimensions: code reuse, quality,
|
|
2418
|
+
efficiency, correctness. Fix agents address the findings. Re-review until only nits
|
|
2419
|
+
remain. Multiple agents auditing each other produces better results than any single
|
|
2420
|
+
agent reviewing its own work.
|
|
2421
|
+
|
|
2422
|
+
The rule: never let 2+ stages complete without critique. Small issues compound into
|
|
2423
|
+
architectural problems if unchecked.
|
|
2424
|
+
|
|
2425
|
+
### 7. Evidence Over Assumptions
|
|
2426
|
+
|
|
2427
|
+
Validation requires PROOF \u2014 command output, test results, HTTP responses. "The code
|
|
2428
|
+
looks correct" is not evidence. "All 14 tests pass" is. This catches the gap between
|
|
2429
|
+
code that looks right and code that works.
|
|
2430
|
+
|
|
2431
|
+
## Architecture Overview
|
|
2432
|
+
|
|
2433
|
+
\`\`\`
|
|
2434
|
+
\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
|
|
2435
|
+
\u2502 USER'S TMUX SESSION \u2502
|
|
2436
|
+
\u2502 \u2502
|
|
2437
|
+
\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
|
|
2438
|
+
\u2502 \u2502 Window 1: Claude Code \u2502 \u2502 Window 2: Dashboard (TUI) \u2502 \u2502
|
|
2439
|
+
\u2502 \u2502 \u2502 \u2502 \u2502 \u2502
|
|
2440
|
+
\u2502 \u2502 User's normal work \u2502 \u2502 Real-time session monitor \u2502 \u2502
|
|
2441
|
+
\u2502 \u2502 + this conversation \u2502 \u2502 Roadmap, agents, reports \u2502 \u2502
|
|
2442
|
+
\u2502 \u2502 \u2502 \u2502 Interactive controls \u2502 \u2502
|
|
2443
|
+
\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
|
|
2444
|
+
\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
|
|
2445
|
+
\u2502 Right Option+s / Right Option+Shift+s
|
|
2446
|
+
\u25BC
|
|
2447
|
+
\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
|
|
2448
|
+
\u2502 SISYPHUS TMUX SESSION \u2502
|
|
2449
|
+
\u2502 (created per sisyphus session) \u2502
|
|
2450
|
+
\u2502 \u2502
|
|
2451
|
+
\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
|
|
2452
|
+
\u2502 \u2502 Orch \u2502 Agent \u2502 Agent \u2502 Agent \u2502 \u2190 panes \u2502
|
|
2453
|
+
\u2502 \u2502 (yellow) \u2502 (blue) \u2502 (green) \u2502 (magenta)\u2502 \u2502
|
|
2454
|
+
\u2502 \u2502 \u2502 \u2502 \u2502 \u2502 \u2502
|
|
2455
|
+
\u2502 \u2502 Plans, \u2502 Impl \u2502 Tests \u2502 Docs \u2502 \u2190 each is a \u2502
|
|
2456
|
+
\u2502 \u2502 assigns, \u2502 feature \u2502 \u2502 \u2502 Claude Code \u2502
|
|
2457
|
+
\u2502 \u2502 reviews \u2502 \u2502 \u2502 \u2502 instance \u2502
|
|
2458
|
+
\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
|
|
2459
|
+
\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
|
|
2460
|
+
\u2502
|
|
2461
|
+
\u25BC
|
|
2462
|
+
\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
|
|
2463
|
+
\u2502 DAEMON (sisyphusd) \u2502
|
|
2464
|
+
\u2502 Background process via launchd \u2502
|
|
2465
|
+
\u2502 \u2502
|
|
2466
|
+
\u2502 Listens on ~/.sisyphus/daemon.sock \u2502
|
|
2467
|
+
\u2502 Manages session lifecycle, pane monitoring, state persistence \u2502
|
|
2468
|
+
\u2502 Polls panes to detect when agents/orchestrator finish \u2502
|
|
2469
|
+
\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
|
|
2470
|
+
\`\`\`
|
|
2471
|
+
|
|
2472
|
+
## The Session Lifecycle (in detail)
|
|
2473
|
+
|
|
2474
|
+
\`\`\`
|
|
2475
|
+
\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
|
|
2476
|
+
\u2502 SESSION LIFECYCLE \u2502
|
|
2477
|
+
\u2502 \u2502
|
|
2478
|
+
\u2502 sisyphus start "task" \u2502
|
|
2479
|
+
\u2502 \u2502 \u2502
|
|
2480
|
+
\u2502 \u25BC \u2502
|
|
2481
|
+
\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
|
|
2482
|
+
\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
|
|
2483
|
+
\u2502 \u2502 plans \u2502 then yields \u2502 in parallel \u2502 \u2502
|
|
2484
|
+
\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
|
|
2485
|
+
\u2502 \u2502 \u2502 each calls \u2502
|
|
2486
|
+
\u2502 \u2502 orchestrator \u2502 sisyphus submit \u2502
|
|
2487
|
+
\u2502 \u2502 is KILLED \u2502 when done \u2502
|
|
2488
|
+
\u2502 \u2502 \u25BC \u2502
|
|
2489
|
+
\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2490
|
+
\u2502 \u2502 \u2502 All agents \u2502 \u2502
|
|
2491
|
+
\u2502 \u2502 \u2502 finished? \u2502 \u2502
|
|
2492
|
+
\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2493
|
+
\u2502 \u2502 \u2502 yes \u2502
|
|
2494
|
+
\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
|
|
2495
|
+
\u2502 \u2502 \u25BC \u2502
|
|
2496
|
+
\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2497
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500 \u2502 Respawn \u2502 Fresh orchestrator with full state \u2502
|
|
2498
|
+
\u2502 next cycle \u2502 Orch \u2502 Reviews reports, plans next cycle \u2502
|
|
2499
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2500
|
+
\u2502 \u2502 \u2502
|
|
2501
|
+
\u2502 \u25BC \u2502
|
|
2502
|
+
\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
|
|
2503
|
+
\u2502 \u2502 More work \u2502\u2500\u2500yes\u2500\u2500\u2192 \u2502 Spawn \u2502 \u2192 (loop) \u2502
|
|
2504
|
+
\u2502 \u2502 needed? \u2502 \u2502 agents \u2502 \u2502
|
|
2505
|
+
\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
|
|
2506
|
+
\u2502 \u2502 no \u2502
|
|
2507
|
+
\u2502 \u25BC \u2502
|
|
2508
|
+
\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
2509
|
+
\u2502 \u2502 sisyphus \u2502 \u2502
|
|
2510
|
+
\u2502 \u2502 complete \u2502 \u2502
|
|
2511
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
2512
|
+
\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
|
|
2513
|
+
\`\`\`
|
|
2514
|
+
|
|
2515
|
+
**Key insight**: The orchestrator is STATELESS. It gets killed after each yield and
|
|
2516
|
+
respawned fresh with the complete session state (roadmap, agent reports, cycle history).
|
|
2517
|
+
This means it never runs out of context, no matter how many cycles a session takes.
|
|
2518
|
+
|
|
2519
|
+
## The Dashboard
|
|
2520
|
+
|
|
2521
|
+
The dashboard is a real-time TUI that shows session state. Launch with \`sisyphus dashboard\`
|
|
2522
|
+
or it auto-opens when a session starts.
|
|
2523
|
+
|
|
2524
|
+
**Dashboard sections:**
|
|
2525
|
+
- **Header**: Session ID, status, task description
|
|
2526
|
+
- **Roadmap**: Current strategic plan with checked/unchecked items
|
|
2527
|
+
- **Agents**: List of all agents with status, duration, and report summaries
|
|
2528
|
+
- **Cycles**: Orchestrator cycle history
|
|
2529
|
+
- **Messages**: Recent session messages
|
|
2530
|
+
|
|
2531
|
+
**Dashboard keys:**
|
|
2532
|
+
| Key | Action |
|
|
2533
|
+
|-----|--------|
|
|
2534
|
+
| \`m\` | Message the orchestrator (steer direction mid-session) |
|
|
2535
|
+
| \`w\` | Jump to the sisyphus tmux session (watch agents work) |
|
|
2536
|
+
| \`k\` | Kill the session |
|
|
2537
|
+
| \`r\` | Resume a paused/completed session |
|
|
2538
|
+
| \`q\` | Quit the dashboard |
|
|
2539
|
+
| \`\u2191/\u2193\` | Scroll through content |
|
|
2540
|
+
| \`Tab\` | Cycle through sections |
|
|
2541
|
+
|
|
2542
|
+
**The \`m\` key is the most powerful feature.** You can message the orchestrator at any time
|
|
2543
|
+
to course-correct: "Focus on the API layer first", "Skip the tests for now",
|
|
2544
|
+
"The approach for auth is wrong, use JWT instead". The orchestrator reads these
|
|
2545
|
+
messages when it respawns each cycle.
|
|
2546
|
+
|
|
2547
|
+
## Monitoring Strategy
|
|
2548
|
+
|
|
2549
|
+
Sisyphus sessions should be actively monitored. Here's what to watch for:
|
|
2550
|
+
|
|
2551
|
+
**Things that go wrong:**
|
|
2552
|
+
- Agents stuck waiting for user input (they're autonomous \u2014 they shouldn't need input)
|
|
2553
|
+
- Agents going down rabbit holes or working on the wrong thing
|
|
2554
|
+
- Merge conflicts between agents touching the same files
|
|
2555
|
+
- Orchestrator spawning too many agents or too few
|
|
2556
|
+
- Agents crashing or getting killed unexpectedly
|
|
2557
|
+
|
|
2558
|
+
**When to intervene:**
|
|
2559
|
+
- Use \`m\` in the dashboard to message the orchestrator with corrections
|
|
2560
|
+
- Use \`sisyphus kill <id>\` to stop a runaway session
|
|
2561
|
+
- Use \`sisyphus resume <id> "new instructions"\` to restart with different direction
|
|
2562
|
+
|
|
2563
|
+
**Useful monitoring commands:**
|
|
2564
|
+
\`\`\`
|
|
2565
|
+
sisyphus status <id> # Quick status check
|
|
2566
|
+
sisyphus status --verbose <id> # Full detail: roadmap, pane output, agent instructions
|
|
2567
|
+
sisyphus dashboard # Interactive TUI
|
|
2568
|
+
tail -f ~/.sisyphus/daemon.log # Daemon activity log
|
|
2569
|
+
\`\`\`
|
|
2570
|
+
|
|
2571
|
+
## The .sisyphus/ Directory
|
|
2572
|
+
|
|
2573
|
+
Everything sisyphus does lives in a \`.sisyphus/\` directory at the root of your project.
|
|
2574
|
+
This is project-local \u2014 each project gets its own. It contains:
|
|
2575
|
+
|
|
2576
|
+
\`\`\`
|
|
2577
|
+
.sisyphus/
|
|
2578
|
+
\u251C\u2500\u2500 config.json # Project-specific config (model, poll interval, etc.)
|
|
2579
|
+
\u251C\u2500\u2500 orchestrator.md # Optional custom orchestrator prompt override
|
|
2580
|
+
\u2514\u2500\u2500 sessions/
|
|
2581
|
+
\u251C\u2500\u2500 <session-id-1>/ # Each session gets its own directory
|
|
2582
|
+
\u251C\u2500\u2500 <session-id-2>/
|
|
2583
|
+
\u2514\u2500\u2500 ...
|
|
2584
|
+
\`\`\`
|
|
2585
|
+
|
|
2586
|
+
There's also a global directory at \`~/.sisyphus/\` for the daemon socket, PID file,
|
|
2587
|
+
logs, keybind scripts, and global config. But the session state \u2014 the roadmaps,
|
|
2588
|
+
reports, context files, cycle logs \u2014 all lives in your project's \`.sisyphus/sessions/\`.
|
|
2589
|
+
|
|
2590
|
+
## Session Files
|
|
2591
|
+
|
|
2592
|
+
Every session creates a directory at \`.sisyphus/sessions/<id>/\` with:
|
|
2593
|
+
|
|
2594
|
+
\`\`\`
|
|
2595
|
+
.sisyphus/sessions/<id>/
|
|
2596
|
+
\u251C\u2500\u2500 state.json # Session state (agents, cycles, status)
|
|
2597
|
+
\u251C\u2500\u2500 roadmap.md # Strategic plan (updated by orchestrator each cycle)
|
|
2598
|
+
\u251C\u2500\u2500 goal.md # Original task description
|
|
2599
|
+
\u251C\u2500\u2500 strategy.md # High-level strategy notes
|
|
2600
|
+
\u251C\u2500\u2500 logs/
|
|
2601
|
+
\u2502 \u251C\u2500\u2500 cycle-000.md # What the orchestrator did in cycle 0
|
|
2602
|
+
\u2502 \u251C\u2500\u2500 cycle-001.md # What it did in cycle 1, etc.
|
|
2603
|
+
\u2502 \u2514\u2500\u2500 ...
|
|
2604
|
+
\u251C\u2500\u2500 reports/
|
|
2605
|
+
\u2502 \u251C\u2500\u2500 agent-001-final.md # Agent's final report
|
|
2606
|
+
\u2502 \u251C\u2500\u2500 agent-002-update.md # Agent's progress update
|
|
2607
|
+
\u2502 \u2514\u2500\u2500 ...
|
|
2608
|
+
\u251C\u2500\u2500 prompts/ # System/user prompts sent to orchestrator and agents
|
|
2609
|
+
\u2514\u2500\u2500 context/ # Shared context files for agents
|
|
2610
|
+
\`\`\`
|
|
2611
|
+
|
|
2612
|
+
## Configuration
|
|
2613
|
+
|
|
2614
|
+
**Global config**: \`~/.sisyphus/config.json\`
|
|
2615
|
+
**Project config**: \`.sisyphus/config.json\` (overrides global)
|
|
2616
|
+
|
|
2617
|
+
Options:
|
|
2618
|
+
- \`model\` \u2014 Claude model for orchestrator and agents
|
|
2619
|
+
- \`orchestratorPrompt\` \u2014 Path to custom orchestrator prompt
|
|
2620
|
+
- \`pollIntervalMs\` \u2014 How often daemon checks pane status (default: 2000)
|
|
2621
|
+
|
|
2622
|
+
## Starting Sessions \u2014 Best Practices
|
|
2623
|
+
|
|
2624
|
+
**The /sisyphus:begin slash command** is the recommended way to start. Inside Claude Code:
|
|
2625
|
+
\`\`\`
|
|
2626
|
+
/sisyphus:begin
|
|
2627
|
+
\`\`\`
|
|
2628
|
+
Then describe your task. Claude will hand it off with the right context.
|
|
2629
|
+
|
|
2630
|
+
**Direct CLI:**
|
|
2631
|
+
\`\`\`
|
|
2632
|
+
sisyphus start "task description" -c "background context"
|
|
2633
|
+
sisyphus start "Implement @requirements.md" -n my-feature
|
|
2634
|
+
\`\`\`
|
|
2635
|
+
|
|
2636
|
+
**Reference files with @**: \`sisyphus start "Build @docs/spec.md"\` \u2014 the orchestrator
|
|
2637
|
+
will read the referenced file as part of its planning.
|
|
2638
|
+
|
|
2639
|
+
**The -c flag** adds background context the orchestrator sees but doesn't act on directly.
|
|
2640
|
+
Use it for constraints: \`-c "Don't modify the auth module, use the existing API"\`
|
|
2641
|
+
|
|
2642
|
+
**The -n flag** gives the session a human-readable name for easier tracking.
|
|
2643
|
+
|
|
2644
|
+
## CLI Command Reference
|
|
2645
|
+
|
|
2646
|
+
| Command | Purpose |
|
|
2647
|
+
|---------|---------|
|
|
2648
|
+
| \`sisyphus start "task"\` | Start a new session |
|
|
2649
|
+
| \`sisyphus status [id]\` | Check session status |
|
|
2650
|
+
| \`sisyphus status -v [id]\` | Detailed status with pane output |
|
|
2651
|
+
| \`sisyphus list\` | List all sessions |
|
|
2652
|
+
| \`sisyphus dashboard\` | Open the TUI dashboard |
|
|
2653
|
+
| \`sisyphus resume <id> "msg"\` | Resume with new instructions |
|
|
2654
|
+
| \`sisyphus kill <id>\` | Stop a session |
|
|
2655
|
+
| \`sisyphus doctor\` | Check installation health |
|
|
2656
|
+
| \`sisyphus setup\` | Run setup/onboarding |
|
|
2657
|
+
| \`sisyphus setup-keybind\` | Install tmux keybinds |
|
|
2658
|
+
|
|
2659
|
+
## Troubleshooting
|
|
2660
|
+
|
|
2661
|
+
**Daemon not running:**
|
|
2662
|
+
\`\`\`
|
|
2663
|
+
sisyphusd restart
|
|
2664
|
+
\`\`\`
|
|
2665
|
+
|
|
2666
|
+
**Keybinds not working (special characters appear):**
|
|
2667
|
+
iTerm2 \u2192 Settings \u2192 Profiles \u2192 Keys \u2192 Right Option Key \u2192 Esc+
|
|
2668
|
+
|
|
2669
|
+
**Agents stuck:** Check \`sisyphus status --verbose <id>\` to see pane output. If an
|
|
2670
|
+
agent is waiting for input, kill the session and restart with clearer instructions.
|
|
2671
|
+
|
|
2672
|
+
**Dashboard not opening:** Run \`sisyphus dashboard\` manually. Must be inside tmux.
|
|
2673
|
+
|
|
2674
|
+
**Session seems hung:** Check \`tail -20 ~/.sisyphus/daemon.log\` for errors.
|
|
2675
|
+
The daemon polls panes every 2s \u2014 if a pane dies unexpectedly, it'll be detected.
|
|
2005
2676
|
</claude-instructions>
|
|
2006
2677
|
`);
|
|
2007
2678
|
}
|
|
2008
|
-
var STEPS = [printStep0, printStep1, printStep2, printStep3, printStep4];
|
|
2679
|
+
var STEPS = [printStep0, printStep1, printStep2, printStep3, printStep4, printStep5];
|
|
2009
2680
|
function registerGettingStarted(program2) {
|
|
2010
|
-
program2.command("getting-started").description("Interactive tutorial (best with Claude Code)").option("--tutorial <step>", "Tutorial step (0-
|
|
2681
|
+
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) => {
|
|
2682
|
+
if (opts.explain) {
|
|
2683
|
+
printExplain();
|
|
2684
|
+
return;
|
|
2685
|
+
}
|
|
2011
2686
|
if (opts.tutorial !== void 0) {
|
|
2012
2687
|
const step = opts.tutorial;
|
|
2013
|
-
if (step < 0 || step >
|
|
2014
|
-
console.error(`Invalid tutorial step: ${opts.tutorial}. Must be 0-
|
|
2688
|
+
if (step < 0 || step > 5 || Number.isNaN(step)) {
|
|
2689
|
+
console.error(`Invalid tutorial step: ${opts.tutorial}. Must be 0-5.`);
|
|
2015
2690
|
process.exit(1);
|
|
2016
2691
|
}
|
|
2017
2692
|
STEPS[step]();
|
|
@@ -2026,8 +2701,8 @@ function registerGettingStarted(program2) {
|
|
|
2026
2701
|
}
|
|
2027
2702
|
|
|
2028
2703
|
// src/cli/commands/init.ts
|
|
2029
|
-
import { existsSync as
|
|
2030
|
-
import { join as
|
|
2704
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
2705
|
+
import { join as join7 } from "path";
|
|
2031
2706
|
var DEFAULT_CONFIG = {};
|
|
2032
2707
|
var ORCHESTRATOR_TEMPLATE = `# Custom Orchestrator Prompt
|
|
2033
2708
|
|
|
@@ -2038,9 +2713,9 @@ var ORCHESTRATOR_TEMPLATE = `# Custom Orchestrator Prompt
|
|
|
2038
2713
|
function registerInit(program2) {
|
|
2039
2714
|
program2.command("init").description("Initialize sisyphus configuration for this project").option("--orchestrator", "Also create a custom orchestrator prompt template").action((opts) => {
|
|
2040
2715
|
const cwd = process.cwd();
|
|
2041
|
-
const sisDir =
|
|
2042
|
-
const configPath =
|
|
2043
|
-
if (
|
|
2716
|
+
const sisDir = join7(cwd, ".sisyphus");
|
|
2717
|
+
const configPath = join7(sisDir, "config.json");
|
|
2718
|
+
if (existsSync7(configPath)) {
|
|
2044
2719
|
console.log(`Already initialized: ${configPath}`);
|
|
2045
2720
|
return;
|
|
2046
2721
|
}
|
|
@@ -2048,8 +2723,8 @@ function registerInit(program2) {
|
|
|
2048
2723
|
writeFileSync4(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n", "utf-8");
|
|
2049
2724
|
console.log(`Created ${configPath}`);
|
|
2050
2725
|
if (opts.orchestrator) {
|
|
2051
|
-
const orchPath =
|
|
2052
|
-
if (!
|
|
2726
|
+
const orchPath = join7(sisDir, "orchestrator.md");
|
|
2727
|
+
if (!existsSync7(orchPath)) {
|
|
2053
2728
|
writeFileSync4(orchPath, ORCHESTRATOR_TEMPLATE, "utf-8");
|
|
2054
2729
|
console.log(`Created ${orchPath}`);
|
|
2055
2730
|
}
|
|
@@ -2064,10 +2739,10 @@ function registerInit(program2) {
|
|
|
2064
2739
|
}
|
|
2065
2740
|
|
|
2066
2741
|
// src/cli/commands/setup.ts
|
|
2067
|
-
import { execSync as
|
|
2742
|
+
import { execSync as execSync10 } from "child_process";
|
|
2068
2743
|
function getTmuxVersion() {
|
|
2069
2744
|
try {
|
|
2070
|
-
return
|
|
2745
|
+
return execSync10("tmux -V", { encoding: "utf-8", stdio: "pipe" }).trim();
|
|
2071
2746
|
} catch {
|
|
2072
2747
|
return "installed";
|
|
2073
2748
|
}
|
|
@@ -2160,7 +2835,7 @@ if (nodeVersion < 22) {
|
|
|
2160
2835
|
var program = new Command();
|
|
2161
2836
|
program.name("sisyphus").description("tmux-integrated orchestration daemon for Claude Code").version(
|
|
2162
2837
|
JSON.parse(
|
|
2163
|
-
readFileSync5(
|
|
2838
|
+
readFileSync5(join8(dirname4(fileURLToPath4(import.meta.url)), "..", "package.json"), "utf-8")
|
|
2164
2839
|
).version
|
|
2165
2840
|
);
|
|
2166
2841
|
program.configureHelp({
|
|
@@ -2203,7 +2878,7 @@ Run 'sisyphus getting-started' for a complete usage guide.
|
|
|
2203
2878
|
var args = process.argv.slice(2);
|
|
2204
2879
|
var firstArg = args[0];
|
|
2205
2880
|
var skipWelcome = ["doctor", "getting-started", "help", "--help", "-h", "init", "setup", "uninstall", "--version", "-V"];
|
|
2206
|
-
if (!
|
|
2881
|
+
if (!existsSync8(globalDir()) && firstArg && !skipWelcome.includes(firstArg)) {
|
|
2207
2882
|
mkdirSync5(globalDir(), { recursive: true });
|
|
2208
2883
|
console.log("");
|
|
2209
2884
|
console.log(" Welcome to Sisyphus. Run 'sisyphus setup' to get started.");
|