@ekkos/cli 1.0.34 → 1.0.36

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.
Files changed (44) hide show
  1. package/dist/capture/jsonl-rewriter.js +72 -7
  2. package/dist/commands/dashboard.js +186 -557
  3. package/dist/commands/init.js +3 -15
  4. package/dist/commands/run.js +222 -256
  5. package/dist/commands/setup.js +0 -47
  6. package/dist/commands/swarm-dashboard.js +4 -13
  7. package/dist/deploy/instructions.d.ts +2 -5
  8. package/dist/deploy/instructions.js +8 -11
  9. package/dist/deploy/settings.js +21 -15
  10. package/dist/deploy/skills.d.ts +0 -8
  11. package/dist/deploy/skills.js +0 -26
  12. package/dist/index.js +2 -2
  13. package/dist/lib/usage-parser.js +1 -2
  14. package/dist/utils/platform.d.ts +0 -3
  15. package/dist/utils/platform.js +1 -4
  16. package/dist/utils/session-binding.d.ts +1 -1
  17. package/dist/utils/session-binding.js +2 -3
  18. package/package.json +1 -1
  19. package/templates/agents/README.md +182 -0
  20. package/templates/agents/code-reviewer.md +166 -0
  21. package/templates/agents/debug-detective.md +169 -0
  22. package/templates/agents/ekkOS_Vercel.md +99 -0
  23. package/templates/agents/extension-manager.md +229 -0
  24. package/templates/agents/git-companion.md +185 -0
  25. package/templates/agents/github-test-agent.md +321 -0
  26. package/templates/agents/railway-manager.md +179 -0
  27. package/templates/hooks/assistant-response.ps1 +26 -94
  28. package/templates/hooks/lib/count-tokens.cjs +0 -0
  29. package/templates/hooks/lib/ekkos-reminders.sh +0 -0
  30. package/templates/hooks/session-start.ps1 +224 -61
  31. package/templates/hooks/session-start.sh +1 -1
  32. package/templates/hooks/stop.ps1 +249 -103
  33. package/templates/hooks/stop.sh +1 -1
  34. package/templates/hooks/user-prompt-submit.ps1 +519 -129
  35. package/templates/hooks/user-prompt-submit.sh +2 -2
  36. package/templates/plan-template.md +0 -0
  37. package/templates/spec-template.md +0 -0
  38. package/templates/windsurf-hooks/before-submit-prompt.sh +238 -0
  39. package/templates/windsurf-hooks/install.sh +0 -0
  40. package/templates/windsurf-hooks/lib/contract.sh +0 -0
  41. package/templates/windsurf-hooks/post-cascade-response.sh +0 -0
  42. package/templates/windsurf-hooks/pre-user-prompt.sh +0 -0
  43. package/templates/windsurf-skills/ekkos-memory/SKILL.md +219 -0
  44. package/README.md +0 -57
@@ -1,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
36
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
4
  };
@@ -384,20 +351,6 @@ async function setupWindsurf(apiKey) {
384
351
  (0, fs_1.mkdirSync)(windsurfDir, { recursive: true });
385
352
  }
386
353
  (0, fs_1.writeFileSync)((0, path_1.join)(windsurfDir, 'ekkos.json'), JSON.stringify({ apiKey }, null, 2));
387
- // Deploy Windsurf skills (Agent Skills spec — 6 Golden Loop skills)
388
- const skillsDir = (0, path_1.join)(codeiumDir, 'skills');
389
- if (!(0, fs_1.existsSync)(skillsDir)) {
390
- (0, fs_1.mkdirSync)(skillsDir, { recursive: true });
391
- }
392
- try {
393
- const { deployWindsurfSkills } = await Promise.resolve().then(() => __importStar(require('../deploy/skills.js')));
394
- const result = deployWindsurfSkills();
395
- console.log(chalk_1.default.green(` ✓ Deployed ${result.count} skills: ${result.skills.join(', ')}`));
396
- }
397
- catch {
398
- // Fallback: templates might not be available in setup path
399
- console.log(chalk_1.default.yellow(' Note: Skills templates not found. Run `ekkos init --ide windsurf` to deploy skills.'));
400
- }
401
354
  // Create project rules template
402
355
  const cascadeRules = generateCascadeRules();
403
356
  const cascadeRulesPath = (0, path_1.join)(process.cwd(), '.windsurfrules');
@@ -582,19 +582,10 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
582
582
  // ── Usage window (Anthropic OAuth) ──
583
583
  async function fetchAnthropicUsage() {
584
584
  try {
585
- let token = null;
586
- if (process.platform === 'darwin') {
587
- const { execSync } = require('child_process');
588
- const credsJson = execSync('security find-generic-password -s "Claude Code-credentials" -w', { encoding: 'utf-8', timeout: 5000 }).trim();
589
- token = JSON.parse(credsJson)?.claudeAiOauth?.accessToken ?? null;
590
- }
591
- else if (process.platform === 'win32') {
592
- const credsPath = path.join(os.homedir(), '.claude', '.credentials.json');
593
- if (require('fs').existsSync(credsPath)) {
594
- const creds = JSON.parse(require('fs').readFileSync(credsPath, 'utf-8'));
595
- token = creds?.claudeAiOauth?.accessToken ?? null;
596
- }
597
- }
585
+ const { execSync } = require('child_process');
586
+ const credsJson = execSync('security find-generic-password -s "Claude Code-credentials" -w', { encoding: 'utf-8', timeout: 5000 }).trim();
587
+ const creds = JSON.parse(credsJson);
588
+ const token = creds?.claudeAiOauth?.accessToken;
598
589
  if (!token)
599
590
  return null;
600
591
  const resp = await fetch('https://api.anthropic.com/api/oauth/usage', {
@@ -1,12 +1,9 @@
1
1
  /**
2
- * Deploy ekkOS instructions to ~/.claude/rules/ekkos.md
3
- *
4
- * Uses Claude Code's user-level rules directory — auto-loaded for all projects
5
- * without touching the user's existing CLAUDE.md.
2
+ * Deploy CLAUDE.md to ~/.claude/CLAUDE.md
6
3
  */
7
4
  export declare function deployInstructions(): void;
8
5
  /**
9
- * Check if ekkOS instructions are deployed
6
+ * Check if CLAUDE.md is deployed
10
7
  */
11
8
  export declare function isInstructionsDeployed(): boolean;
12
9
  /**
@@ -7,24 +7,21 @@ const fs_1 = require("fs");
7
7
  const platform_1 = require("../utils/platform");
8
8
  const templates_1 = require("../utils/templates");
9
9
  /**
10
- * Deploy ekkOS instructions to ~/.claude/rules/ekkos.md
11
- *
12
- * Uses Claude Code's user-level rules directory — auto-loaded for all projects
13
- * without touching the user's existing CLAUDE.md.
10
+ * Deploy CLAUDE.md to ~/.claude/CLAUDE.md
14
11
  */
15
12
  function deployInstructions() {
16
- // Ensure ~/.claude/rules/ exists
17
- if (!(0, fs_1.existsSync)(platform_1.CLAUDE_RULES_DIR)) {
18
- (0, fs_1.mkdirSync)(platform_1.CLAUDE_RULES_DIR, { recursive: true });
13
+ // Ensure .claude directory exists
14
+ if (!(0, fs_1.existsSync)(platform_1.CLAUDE_DIR)) {
15
+ (0, fs_1.mkdirSync)(platform_1.CLAUDE_DIR, { recursive: true });
19
16
  }
20
- // Deploy to rules/ekkos.md (safe to overwrite — this is our file)
21
- (0, templates_1.copyTemplateFile)('CLAUDE.md', platform_1.CLAUDE_EKKOS_RULES);
17
+ // Copy CLAUDE.md template
18
+ (0, templates_1.copyTemplateFile)('CLAUDE.md', platform_1.CLAUDE_MD);
22
19
  }
23
20
  /**
24
- * Check if ekkOS instructions are deployed
21
+ * Check if CLAUDE.md is deployed
25
22
  */
26
23
  function isInstructionsDeployed() {
27
- return (0, fs_1.existsSync)(platform_1.CLAUDE_EKKOS_RULES);
24
+ return (0, fs_1.existsSync)(platform_1.CLAUDE_MD);
28
25
  }
29
26
  /**
30
27
  * Get the CLAUDE.md content (for preview)
@@ -3,38 +3,43 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deployClaudeSettings = deployClaudeSettings;
4
4
  exports.areHooksConfigured = areHooksConfigured;
5
5
  const fs_1 = require("fs");
6
- const path_1 = require("path");
7
6
  const platform_1 = require("../utils/platform");
8
7
  /**
9
8
  * Generate the hooks configuration for Claude Code settings.json
10
- * Uses the new format required by Claude Code 2.1.40+
11
9
  */
12
10
  function generateHooksConfig() {
13
- // Use path.join (via CLAUDE_HOOKS_DIR) so OS-correct separators are used.
14
- // JSON.stringify handles backslash-escaping automatically — do NOT pre-escape.
15
- //
16
- // IMPORTANT: Do NOT use `-File` on Windows — Claude Code has a known bug where
17
- // it fails to canonicalize absolute script paths, producing "system cannot find
18
- // the specified path". Use `-Command "& 'path'"` instead, which bypasses it.
19
- // See: https://github.com/anthropics/claude-code/issues/12874
11
+ const hooksDir = `${platform_1.HOME_DIR}/.claude/hooks`;
20
12
  if (platform_1.isWindows) {
13
+ // Windows uses PowerShell
21
14
  return {
15
+ SessionStart: [
16
+ { type: 'command', command: `powershell -ExecutionPolicy Bypass -File "${hooksDir}/session-start.ps1"` }
17
+ ],
22
18
  UserPromptSubmit: [
23
- { hooks: [{ type: 'command', command: `powershell -ExecutionPolicy Bypass -Command "& '${(0, path_1.join)(platform_1.CLAUDE_HOOKS_DIR, 'user-prompt-submit.ps1')}'"` }] }
19
+ { type: 'command', command: `powershell -ExecutionPolicy Bypass -File "${hooksDir}/user-prompt-submit.ps1"` }
24
20
  ],
25
21
  Stop: [
26
- { hooks: [{ type: 'command', command: `powershell -ExecutionPolicy Bypass -Command "& '${(0, path_1.join)(platform_1.CLAUDE_HOOKS_DIR, 'stop.ps1')}'"` }] }
22
+ { type: 'command', command: `powershell -ExecutionPolicy Bypass -File "${hooksDir}/stop.ps1"` }
27
23
  ],
24
+ AssistantResponse: [
25
+ { type: 'command', command: `powershell -ExecutionPolicy Bypass -File "${hooksDir}/assistant-response.ps1"` }
26
+ ]
28
27
  };
29
28
  }
30
- // Unix: forward slashes, no quoting needed
29
+ // Unix uses bash
31
30
  return {
31
+ SessionStart: [
32
+ { type: 'command', command: `bash ${hooksDir}/session-start.sh` }
33
+ ],
32
34
  UserPromptSubmit: [
33
- { hooks: [{ type: 'command', command: `bash ${(0, path_1.join)(platform_1.CLAUDE_HOOKS_DIR, 'user-prompt-submit.sh')}` }] }
35
+ { type: 'command', command: `bash ${hooksDir}/user-prompt-submit.sh` }
34
36
  ],
35
37
  Stop: [
36
- { hooks: [{ type: 'command', command: `bash ${(0, path_1.join)(platform_1.CLAUDE_HOOKS_DIR, 'stop.sh')}` }] }
38
+ { type: 'command', command: `bash ${hooksDir}/stop.sh` }
37
39
  ],
40
+ AssistantResponse: [
41
+ { type: 'command', command: `bash ${hooksDir}/assistant-response.sh` }
42
+ ]
38
43
  };
39
44
  }
40
45
  /**
@@ -69,7 +74,8 @@ function areHooksConfigured() {
69
74
  try {
70
75
  const settings = JSON.parse((0, fs_1.readFileSync)(platform_1.CLAUDE_SETTINGS, 'utf-8'));
71
76
  const hooks = settings.hooks || {};
72
- return Boolean(hooks.UserPromptSubmit?.length &&
77
+ return Boolean(hooks.SessionStart?.length &&
78
+ hooks.UserPromptSubmit?.length &&
73
79
  hooks.Stop?.length);
74
80
  }
75
81
  catch {
@@ -5,14 +5,6 @@ export declare function deploySkills(): {
5
5
  count: number;
6
6
  skills: string[];
7
7
  };
8
- /**
9
- * Deploy Windsurf skills to ~/.codeium/windsurf/skills/
10
- * Uses Agent Skills spec format (lowercase-hyphenated names, SKILL.md)
11
- */
12
- export declare function deployWindsurfSkills(): {
13
- count: number;
14
- skills: string[];
15
- };
16
8
  /**
17
9
  * Check if skills are deployed
18
10
  */
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deploySkills = deploySkills;
4
- exports.deployWindsurfSkills = deployWindsurfSkills;
5
4
  exports.areSkillsDeployed = areSkillsDeployed;
6
5
  exports.countDeployedSkills = countDeployedSkills;
7
6
  exports.listExpectedSkills = listExpectedSkills;
@@ -33,31 +32,6 @@ function deploySkills() {
33
32
  skills: deployedSkills
34
33
  };
35
34
  }
36
- /**
37
- * Deploy Windsurf skills to ~/.codeium/windsurf/skills/
38
- * Uses Agent Skills spec format (lowercase-hyphenated names, SKILL.md)
39
- */
40
- function deployWindsurfSkills() {
41
- if (!(0, fs_1.existsSync)(platform_1.WINDSURF_SKILLS_DIR)) {
42
- (0, fs_1.mkdirSync)(platform_1.WINDSURF_SKILLS_DIR, { recursive: true });
43
- }
44
- const skillNames = (0, templates_1.listTemplateDirs)('windsurf-skills');
45
- const deployedSkills = [];
46
- for (const skillName of skillNames) {
47
- try {
48
- const destPath = `${platform_1.WINDSURF_SKILLS_DIR}/${skillName}`;
49
- (0, templates_1.copyTemplateDir)(`windsurf-skills/${skillName}`, destPath);
50
- deployedSkills.push(skillName);
51
- }
52
- catch (error) {
53
- console.warn(`Warning: Could not deploy Windsurf skill ${skillName}`);
54
- }
55
- }
56
- return {
57
- count: deployedSkills.length,
58
- skills: deployedSkills
59
- };
60
- }
61
35
  /**
62
36
  * Check if skills are deployed
63
37
  */
package/dist/index.js CHANGED
@@ -246,10 +246,10 @@ commander_1.program
246
246
  .option('-d, --doctor', 'Run diagnostics before starting')
247
247
  .option('-r, --research', 'Auto-run research agent on startup (scans arXiv for new AI papers)')
248
248
  .option('--skip-inject', 'Monitor-only mode (detect context wall but print instructions instead of auto-inject)')
249
- .option('--skip-dna', 'Deprecated no-op (legacy ccDNA patching has been removed)')
249
+ .option('--skip-dna', 'Skip ccDNA injection (bypass Claude Code patching)')
250
250
  .option('--skip-proxy', 'Skip API proxy (use direct Anthropic API, disables seamless context eviction)')
251
251
  .option('--dashboard', 'Launch with live usage dashboard in an isolated 60/40 tmux split (requires tmux)')
252
- .option('--kickstart', 'Auto-send "test" on load to create session immediately (manual/debug use)')
252
+ .option('--kickstart', 'Auto-send "test" on load to create session immediately (used internally by --dashboard)')
253
253
  .option('--add-dir <dirs...>', 'Additional directories Claude Code can access (outside working directory)')
254
254
  .action((options) => {
255
255
  (0, run_1.run)({
@@ -79,8 +79,7 @@ function isEkkosSessionName(name) {
79
79
  return /^[a-z]+-[a-z]+-[a-z]+$/.test(name);
80
80
  }
81
81
  function encodeProjectPath(projectPath) {
82
- // Replace all path separators (and Windows drive colon) with '-'
83
- return projectPath.replace(/[:\\/]/g, '-');
82
+ return projectPath.replace(/\//g, '-');
84
83
  }
85
84
  /** Resolve an ekkOS session name to a JSONL UUID */
86
85
  function resolveSessionName(name) {
@@ -15,13 +15,10 @@ export declare const CLAUDE_AGENTS_DIR: string;
15
15
  export declare const CLAUDE_PLUGINS_DIR: string;
16
16
  export declare const CLAUDE_STATE_DIR: string;
17
17
  export declare const CLAUDE_MD: string;
18
- export declare const CLAUDE_RULES_DIR: string;
19
- export declare const CLAUDE_EKKOS_RULES: string;
20
18
  export declare const CURSOR_DIR: string;
21
19
  export declare const CURSOR_MCP: string;
22
20
  export declare const WINDSURF_DIR: string;
23
21
  export declare const WINDSURF_MCP: string;
24
- export declare const WINDSURF_SKILLS_DIR: string;
25
22
  /**
26
23
  * Detect which IDEs are installed on this system
27
24
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WINDSURF_SKILLS_DIR = exports.WINDSURF_MCP = exports.WINDSURF_DIR = exports.CURSOR_MCP = exports.CURSOR_DIR = exports.CLAUDE_EKKOS_RULES = exports.CLAUDE_RULES_DIR = exports.CLAUDE_MD = exports.CLAUDE_STATE_DIR = exports.CLAUDE_PLUGINS_DIR = exports.CLAUDE_AGENTS_DIR = exports.CLAUDE_SKILLS_DIR = exports.CLAUDE_HOOKS_DIR = exports.CLAUDE_SETTINGS = exports.CLAUDE_CONFIG = exports.CLAUDE_DIR = exports.EKKOS_CONFIG = exports.EKKOS_DIR = exports.HOME_DIR = exports.MCP_API_URL = exports.PLATFORM_URL = exports.isLinux = exports.isMac = exports.isWindows = void 0;
3
+ exports.WINDSURF_MCP = exports.WINDSURF_DIR = exports.CURSOR_MCP = exports.CURSOR_DIR = exports.CLAUDE_MD = exports.CLAUDE_STATE_DIR = exports.CLAUDE_PLUGINS_DIR = exports.CLAUDE_AGENTS_DIR = exports.CLAUDE_SKILLS_DIR = exports.CLAUDE_HOOKS_DIR = exports.CLAUDE_SETTINGS = exports.CLAUDE_CONFIG = exports.CLAUDE_DIR = exports.EKKOS_CONFIG = exports.EKKOS_DIR = exports.HOME_DIR = exports.MCP_API_URL = exports.PLATFORM_URL = exports.isLinux = exports.isMac = exports.isWindows = void 0;
4
4
  exports.detectInstalledIDEs = detectInstalledIDEs;
5
5
  exports.detectCurrentIDE = detectCurrentIDE;
6
6
  const os_1 = require("os");
@@ -24,13 +24,10 @@ exports.CLAUDE_AGENTS_DIR = (0, path_1.join)(exports.CLAUDE_DIR, 'agents');
24
24
  exports.CLAUDE_PLUGINS_DIR = (0, path_1.join)(exports.CLAUDE_DIR, 'plugins', 'ekkos');
25
25
  exports.CLAUDE_STATE_DIR = (0, path_1.join)(exports.CLAUDE_DIR, 'state');
26
26
  exports.CLAUDE_MD = (0, path_1.join)(exports.CLAUDE_DIR, 'CLAUDE.md');
27
- exports.CLAUDE_RULES_DIR = (0, path_1.join)(exports.CLAUDE_DIR, 'rules');
28
- exports.CLAUDE_EKKOS_RULES = (0, path_1.join)(exports.CLAUDE_RULES_DIR, 'ekkos.md');
29
27
  exports.CURSOR_DIR = (0, path_1.join)(exports.HOME_DIR, '.cursor');
30
28
  exports.CURSOR_MCP = (0, path_1.join)(exports.CURSOR_DIR, 'mcp.json');
31
29
  exports.WINDSURF_DIR = (0, path_1.join)(exports.HOME_DIR, '.codeium', 'windsurf');
32
30
  exports.WINDSURF_MCP = (0, path_1.join)(exports.WINDSURF_DIR, 'mcp_config.json');
33
- exports.WINDSURF_SKILLS_DIR = (0, path_1.join)(exports.WINDSURF_DIR, 'skills');
34
31
  /**
35
32
  * Detect which IDEs are installed on this system
36
33
  */
@@ -2,4 +2,4 @@
2
2
  * Bind the real session name to the proxy
3
3
  * This replaces the '_pending' placeholder for this user, enabling proper eviction
4
4
  */
5
- export declare function bindSession(realSession: string, projectPath: string, pendingSession?: string): Promise<boolean>;
5
+ export declare function bindSession(realSession: string, projectPath: string): Promise<boolean>;
@@ -7,7 +7,7 @@ const MEMORY_API_URL = process.env.EKKOS_PROXY_URL || 'https://proxy.ekkos.dev';
7
7
  * Bind the real session name to the proxy
8
8
  * This replaces the '_pending' placeholder for this user, enabling proper eviction
9
9
  */
10
- async function bindSession(realSession, projectPath, pendingSession) {
10
+ async function bindSession(realSession, projectPath) {
11
11
  try {
12
12
  // Get userId same way as run.ts
13
13
  const config = (0, state_1.getConfig)();
@@ -33,8 +33,7 @@ async function bindSession(realSession, projectPath, pendingSession) {
33
33
  body: JSON.stringify({
34
34
  userId,
35
35
  realSession,
36
- projectPath,
37
- pendingSession: pendingSession || null,
36
+ projectPath
38
37
  })
39
38
  });
40
39
  return response.ok;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekkos/cli",
3
- "version": "1.0.34",
3
+ "version": "1.0.36",
4
4
  "description": "Setup ekkOS memory for AI coding assistants (Claude Code, Cursor, Windsurf)",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -0,0 +1,182 @@
1
+ # ekkOS Agents
2
+
3
+ Automatic agents that enhance your Claude Code experience with persistent memory and context preservation.
4
+
5
+ ## Installation
6
+
7
+ These agents are automatically installed when you set up ekkos-connect:
8
+
9
+ ```bash
10
+ # During ekkos-connect installation, agents are copied to:
11
+ ~/.claude/agents/
12
+ ```
13
+
14
+ ## Available Agents
15
+
16
+ ### Context Guardian (`context-guardian.json`)
17
+
18
+ **Version:** 3.0.0
19
+ **Solves:** The "95% of issues from compacting" problem in Claude Code
20
+
21
+ **What it does:**
22
+ - Automatically preserves your working memory before Claude Code compaction
23
+ - Seamlessly restores context when you resume (mid-session or new session)
24
+ - Prevents infinite compaction loops with circuit breaker
25
+ - Preserves file read cache to eliminate redundant reads
26
+ - Auto-refreshes directives and CLAUDE.md after restoration
27
+ - Zero user action required - it just works
28
+
29
+ **How it works:**
30
+
31
+ | Trigger | What Happens |
32
+ |---------|--------------|
33
+ | **Pre-Compaction (85-90%)** | Detects token limit → captures state → promotes to ekkOS episodic memory |
34
+ | **Mid-Session (NEW v2.0)** | Checks every interaction → detects compaction → auto-restores silently |
35
+ | **Post-Compaction (NEW v3.0)** | Refreshes directives → injects file cache → user never notices gap |
36
+ | **Session Start** | Checks for snapshot → restores context → injects into conversation |
37
+
38
+ **v3.0 Enhancements (GitHub-Driven):**
39
+
40
+ | Issue | Problem | Solution |
41
+ |-------|---------|----------|
42
+ | #6541, #2222, #2283 | Infinite compaction loops | Circuit breaker with exponential backoff |
43
+ | #11487 | Files re-read 10-15x after compact | File read cache preservation |
44
+ | #3021 | Rules/memory forgotten | Auto-refresh directives + CLAUDE.md |
45
+ | #3274 | Compact blocks normal use | Async preservation at 85% threshold |
46
+ | #5720 | No warning before compact | Optional pre-compaction notification |
47
+
48
+ **Setup:**
49
+
50
+ Add to your shell profile (`.zshrc`, `.bashrc`):
51
+
52
+ ```bash
53
+ # Core Configuration
54
+ export EKKOS_API_URL="https://api.ekkos.dev"
55
+ export EKKOS_API_KEY="ekk_your_key_here"
56
+ export EKKOS_USER_ID="your_user_id"
57
+ export CONTEXT_GUARDIAN_ENABLED="true"
58
+ export CONTEXT_GUARDIAN_AUTO_PRESERVE="true"
59
+ export CONTEXT_GUARDIAN_TOKEN_THRESHOLD="0.90"
60
+
61
+ # Mid-Session Restoration (v2.0)
62
+ export CONTEXT_GUARDIAN_AUTO_RESTORE="true"
63
+ export CONTEXT_GUARDIAN_RESTORATION_WINDOW="300"
64
+ export CONTEXT_GUARDIAN_SILENT_RESTORE="true"
65
+
66
+ # Loop Prevention (v3.0)
67
+ export CONTEXT_GUARDIAN_MAX_COMPACTIONS="5"
68
+ export CONTEXT_GUARDIAN_COOLDOWN_MS="60000"
69
+
70
+ # Directives Refresh (v3.0)
71
+ export CONTEXT_GUARDIAN_REFRESH_DIRECTIVES="true"
72
+ export CONTEXT_GUARDIAN_REREAD_CLAUDE_MD="true"
73
+
74
+ # File Cache (v3.0)
75
+ export CONTEXT_GUARDIAN_PRESERVE_FILE_CACHE="true"
76
+ ```
77
+
78
+ **Get your credentials:**
79
+ ```bash
80
+ # Get API key and user ID
81
+ curl https://api.ekkos.dev/api/v1/me \
82
+ -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
83
+ ```
84
+
85
+ Or visit: https://platform.ekkos.dev/settings/api-keys
86
+
87
+ **Manual commands:**
88
+ - `/preserve` - Manually trigger context preservation
89
+ - `/restore` - Manually trigger context restoration
90
+ - `/snapshot-status` - Check if snapshot exists for current session
91
+ - `/clear-snapshot` - Clear local restoration token
92
+ - `/circuit-status` - Show circuit breaker state (v3.0)
93
+
94
+ **Documentation:** See `context-guardian-guide.md` for complete details.
95
+
96
+ ### GitHub Test Agent (`github-test-agent.md`)
97
+
98
+ **Version:** 1.0.0
99
+ **Solves:** Manual test-fix-push cycles when CI fails
100
+
101
+ **What it does:**
102
+ - Runs GitHub Actions test workflows via `gh` CLI
103
+ - Monitors for completion and parses failure logs
104
+ - Automatically diagnoses and fixes test failures
105
+ - Commits, pushes, and re-runs until green
106
+ - Learns from fixes via ekkOS pattern forging
107
+
108
+ **Self-healing loop:**
109
+ ```
110
+ TRIGGER → POLL → PARSE → FIX → VERIFY → PUSH → LOOP
111
+ ```
112
+
113
+ **Safety rails:**
114
+ - Max 5 fix attempts per session
115
+ - Max 3 attempts for same error
116
+ - Requires approval for architectural changes
117
+ - Local verification before pushing
118
+ - Memory-first debugging (searches patterns before fixing)
119
+
120
+ **Trigger words:** test, CI, workflow, github actions, run tests, fix tests, green build
121
+
122
+ **Example:**
123
+ ```
124
+ User: "Run the extension tests and fix any failures"
125
+ Agent: Triggers workflow → parses failures → fixes code → pushes → loops until green
126
+ ```
127
+
128
+ ---
129
+
130
+ ## How Agents Work
131
+
132
+ Agents run automatically in Claude Code when specific conditions are met:
133
+
134
+ - **Context Guardian:** Runs when token count exceeds threshold, on every user interaction (mid-session check), or on session start
135
+ - Future agents will add more capabilities (pattern suggestions, code review, etc.)
136
+
137
+ ## Technical Details
138
+
139
+ - Agents are JSON configuration files that define:
140
+ - Name and description
141
+ - System prompt (instructions)
142
+ - Available tools (MCP tools they can call)
143
+ - Model to use (sonnet, opus, haiku)
144
+ - Allowed commands (for security)
145
+
146
+ - Agents run with access to your conversation context
147
+ - They can call ekkOS MCP tools to preserve/restore memory
148
+ - They operate silently in the background
149
+
150
+ ## Impact
151
+
152
+ **Context Guardian v3.0 metrics:**
153
+
154
+ | Metric | Before | After v3.0 |
155
+ |--------|--------|------------|
156
+ | Context loss rate | 95% | <1% |
157
+ | Infinite loop incidents | Common | 0% |
158
+ | Redundant file reads | 10-15x | <2x |
159
+ | Directives forgotten | 100% | 0% |
160
+ | Preservation time | 2-5s blocking | <500ms async |
161
+ | Productivity saved | $0 | 50+ hours/dev/year |
162
+ | ROI | N/A | $7.5K/dev/year |
163
+
164
+ ## Version History
165
+
166
+ | Version | Features |
167
+ |---------|----------|
168
+ | v1.0 | Cross-session restoration, local fallback |
169
+ | v2.0 | Mid-session restoration, check-on-every-interaction |
170
+ | v3.0 | Circuit breaker, file cache, directives refresh, async preservation |
171
+
172
+ ## Support
173
+
174
+ - **Issues:** https://github.com/ekkos/ekkos/issues
175
+ - **Docs:** https://docs.ekkos.dev/agents
176
+ - **Email:** support@ekkos.dev
177
+
178
+ ---
179
+
180
+ **Built with ❤️ by ekkOS™**
181
+
182
+ Context Guardian v3.0: Making compaction invisible, one interaction at a time.