lynkr 3.2.1 → 4.0.0

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.
@@ -0,0 +1,1116 @@
1
+ # Learnings from GET SHIT DONE Repository
2
+
3
+ **Source:** https://github.com/glittercowboy/get-shit-done
4
+ **Analyzed:** 2026-01-11
5
+ **Stars:** 1.4k | **Forks:** 191
6
+
7
+ ---
8
+
9
+ ## Executive Summary
10
+
11
+ GET SHIT DONE (GSD) is a meta-prompting system for Claude Code that prevents quality degradation through structured workflows and fresh context management. Key innovation: **breaking work into atomic tasks executed by fresh subagents** rather than long single-session conversations.
12
+
13
+ **What Lynkr does better:**
14
+ - ✅ Multi-provider support (9 providers vs Claude-only)
15
+ - ✅ Token optimization (60-80% reduction via caching, tool selection)
16
+ - ✅ IDE integration (Cursor support, OpenAI API compatibility)
17
+ - ✅ Hybrid routing (local + cloud fallback)
18
+
19
+ **What GSD does better:**
20
+ - ✅ Context management (fresh agents per task)
21
+ - ✅ Atomic task planning (enforced 2-3 task breakdown)
22
+ - ✅ Codebase mapping (7-document parallel analysis)
23
+ - ✅ Git integration (automatic commits per task)
24
+
25
+ ---
26
+
27
+ ## Key Patterns & Missing Features
28
+
29
+ ### 1. Fresh Context Per Task (Multi-Agent Pattern)
30
+
31
+ #### Problem Statement
32
+ **Current behavior in Lynkr:**
33
+ - Single session conversation grows indefinitely
34
+ - As context fills (150k+ tokens), quality degrades
35
+ - Claude starts saying "Due to context limits, I'll be more concise..."
36
+ - User must manually start new session
37
+
38
+ **GSD's solution:**
39
+ - Each task spawns fresh subagent with 200k clean tokens
40
+ - Essential state passed as summary
41
+ - Prevents context pollution
42
+ - Maintains consistent quality
43
+
44
+ #### Implementation Plan
45
+
46
+ **Files to modify:**
47
+ - `src/orchestrator/index.js` - Add context monitoring
48
+ - `src/agents/index.js` - Add task-based spawning
49
+ - `src/config/index.js` - Add context thresholds
50
+
51
+ **Configuration additions:**
52
+ ```javascript
53
+ // .env
54
+ CONTEXT_BUDGET_WARNING=150000 # Warn at 150k tokens
55
+ CONTEXT_BUDGET_MAX=180000 # Hard limit at 180k tokens
56
+ AUTO_SPAWN_SUBAGENT=false # Auto-spawn when hitting limit (default: false)
57
+ SUBAGENT_CONTEXT_SUMMARY_LENGTH=5000 # Summary size for new agent
58
+ ```
59
+
60
+ **Code implementation:**
61
+ ```javascript
62
+ // src/orchestrator/index.js (after line 1500)
63
+
64
+ async function checkContextBudget(session, estimatedTokens) {
65
+ const warningThreshold = config.CONTEXT_BUDGET_WARNING || 150000;
66
+ const maxThreshold = config.CONTEXT_BUDGET_MAX || 180000;
67
+
68
+ if (estimatedTokens > warningThreshold) {
69
+ const utilization = Math.round(estimatedTokens / maxThreshold * 100);
70
+
71
+ logger.warn({
72
+ estimatedTokens,
73
+ warningThreshold,
74
+ maxThreshold,
75
+ utilization: `${utilization}%`
76
+ }, "⚠️ Context approaching budget limit");
77
+
78
+ // Option A: Auto-spawn (aggressive)
79
+ if (config.AUTO_SPAWN_SUBAGENT && estimatedTokens > maxThreshold) {
80
+ return await spawnFreshSubagent(session);
81
+ }
82
+
83
+ // Option B: Inject warning (conservative)
84
+ return {
85
+ warning: true,
86
+ message: `Context budget at ${utilization}%. Consider:
87
+ 1. Breaking current task into smaller subtasks
88
+ 2. Completing current work before starting new tasks
89
+ 3. Starting fresh session for complex work`
90
+ };
91
+ }
92
+
93
+ return { warning: false };
94
+ }
95
+
96
+ async function spawnFreshSubagent(session) {
97
+ const summary = await summarizeSessionState(session, {
98
+ maxLength: config.SUBAGENT_CONTEXT_SUMMARY_LENGTH || 5000,
99
+ include: {
100
+ currentTask: true,
101
+ recentDecisions: true,
102
+ activeFiles: true,
103
+ blockers: true
104
+ }
105
+ });
106
+
107
+ logger.info({
108
+ parentSession: session.id,
109
+ summaryTokens: summary.tokens
110
+ }, "Spawning fresh subagent with summarized context");
111
+
112
+ const { executeAgent } = require("./agents");
113
+ return await executeAgent({
114
+ agentType: "general-purpose",
115
+ task: summary.currentTask,
116
+ context: summary.text,
117
+ maxSteps: 15,
118
+ parentSession: session.id
119
+ });
120
+ }
121
+
122
+ function summarizeSessionState(session, options = {}) {
123
+ const recentTurns = session.messages.slice(-10); // Last 10 turns
124
+ const currentFiles = extractActiveFiles(session.messages);
125
+ const decisions = extractDecisions(session.messages);
126
+ const blockers = extractBlockers(session.messages);
127
+
128
+ const summary = `
129
+ <session-summary>
130
+ <current-task>
131
+ ${extractCurrentTask(recentTurns)}
132
+ </current-task>
133
+
134
+ <active-files>
135
+ ${currentFiles.map(f => `<file>${f}</file>`).join('\n ')}
136
+ </active-files>
137
+
138
+ <recent-decisions>
139
+ ${decisions.map(d => `<decision>${d}</decision>`).join('\n ')}
140
+ </recent-decisions>
141
+
142
+ <blockers>
143
+ ${blockers.map(b => `<blocker>${b}</blocker>`).join('\n ')}
144
+ </blockers>
145
+
146
+ <next-steps>
147
+ ${suggestNextSteps(recentTurns)}
148
+ </next-steps>
149
+ </session-summary>`;
150
+
151
+ return {
152
+ text: summary,
153
+ tokens: estimateTokens(summary)
154
+ };
155
+ }
156
+ ```
157
+
158
+ **Priority:** HIGH
159
+ **Difficulty:** 5/10 (medium)
160
+ **Effort:** 4-6 hours
161
+ **Value:** Prevents quality degradation in long sessions
162
+
163
+ ---
164
+
165
+ ### 2. Atomic Task Planning (Enforced Breakdown)
166
+
167
+ #### Problem Statement
168
+ **Current behavior in Lynkr:**
169
+ - TodoWrite tool exists but not enforced
170
+ - Users can request complex multi-step tasks
171
+ - No automatic breakdown into atomic units
172
+ - No verification of task completeness
173
+
174
+ **GSD's solution:**
175
+ - Enforces 2-3 task maximum per phase
176
+ - Each task has clear completion criteria
177
+ - Tasks are atomic (single focus, discrete)
178
+ - XML-structured for precision
179
+
180
+ #### Implementation Plan
181
+
182
+ **Files to modify:**
183
+ - `src/orchestrator/index.js` - Add task complexity detection
184
+ - `src/utils/task-planner.js` - New file for atomic planning
185
+ - `src/prompts/task-breakdown.js` - Task breakdown prompt
186
+
187
+ **Code implementation:**
188
+ ```javascript
189
+ // src/utils/task-planner.js (NEW FILE)
190
+
191
+ const logger = require("../logger");
192
+ const { estimateTokenCount } = require("./tokens");
193
+
194
+ /**
195
+ * Detect if user request is complex and needs breakdown
196
+ */
197
+ function isComplexTask(userMessage) {
198
+ const complexityIndicators = [
199
+ // Multiple verbs
200
+ /\b(and|then|also|after|before)\b/gi,
201
+ // Multiple files mentioned
202
+ /\b(file|files|folder|folders|directory|directories)\b.*\b(file|files|folder|folders|directory|directories)\b/gi,
203
+ // Multiple actions
204
+ /\b(create|add|update|fix|refactor|implement|write)\b.*\b(create|add|update|fix|refactor|implement|write)\b/gi,
205
+ // Long descriptions (>200 words)
206
+ userMessage.split(/\s+/).length > 200,
207
+ // Multiple features/components
208
+ /\b(feature|component|module|service)\b.*\b(feature|component|module|service)\b/gi
209
+ ];
210
+
211
+ return complexityIndicators.some(indicator =>
212
+ typeof indicator === 'boolean' ? indicator : indicator.test(userMessage)
213
+ );
214
+ }
215
+
216
+ /**
217
+ * Generate atomic task breakdown using LLM
218
+ */
219
+ async function generateAtomicTasks(userMessage, context = {}) {
220
+ const prompt = `
221
+ <task-breakdown-request>
222
+ <user-request>
223
+ ${userMessage}
224
+ </user-request>
225
+
226
+ <context>
227
+ <current-files>
228
+ ${context.files?.join(', ') || 'Unknown'}
229
+ </current-files>
230
+ <tech-stack>
231
+ ${context.stack || 'Unknown'}
232
+ </tech-stack>
233
+ </context>
234
+
235
+ <instructions>
236
+ Break down the user's request into atomic tasks following these rules:
237
+
238
+ 1. Each task must be ATOMIC (single focus, discrete action)
239
+ 2. Maximum 2-3 tasks per phase
240
+ 3. If more than 3 tasks needed, create multiple phases
241
+ 4. Each task must have:
242
+ - Clear name (verb + object, e.g., "Add authentication middleware")
243
+ - Specific files to modify
244
+ - Concrete action description
245
+ - Verification steps
246
+ - Completion criteria
247
+
248
+ Return in XML format:
249
+ <task-plan>
250
+ <phase name="Phase 1 Name">
251
+ <task>
252
+ <name>Task name</name>
253
+ <files>file1.js, file2.js</files>
254
+ <action>What to do</action>
255
+ <verify>How to verify</verify>
256
+ <done>Completion criteria</done>
257
+ </task>
258
+ </phase>
259
+ </task-plan>
260
+ </instructions>
261
+ </task-breakdown-request>`;
262
+
263
+ // Call LLM to generate plan (use fast model like Haiku)
264
+ const response = await invokeModel({
265
+ model: "haiku", // Fast, cheap for planning
266
+ messages: [{ role: "user", content: prompt }],
267
+ max_tokens: 2000
268
+ });
269
+
270
+ return parseTaskPlan(response.content);
271
+ }
272
+
273
+ function parseTaskPlan(xmlContent) {
274
+ // Parse XML into structured task plan
275
+ // Returns: { phases: [{ name, tasks: [{ name, files, action, verify, done }] }] }
276
+ // Implementation uses XML parser or regex extraction
277
+ }
278
+
279
+ module.exports = {
280
+ isComplexTask,
281
+ generateAtomicTasks
282
+ };
283
+ ```
284
+
285
+ **Integration in orchestrator:**
286
+ ```javascript
287
+ // src/orchestrator/index.js
288
+
289
+ const { isComplexTask, generateAtomicTasks } = require("../utils/task-planner");
290
+
291
+ async function processMessage({ payload, headers, session, options }) {
292
+ const userMessage = payload.messages[payload.messages.length - 1].content;
293
+
294
+ // Check if task is complex
295
+ if (isComplexTask(userMessage)) {
296
+ logger.info("Detected complex task, suggesting atomic breakdown");
297
+
298
+ // Generate task plan
299
+ const taskPlan = await generateAtomicTasks(userMessage, {
300
+ files: extractFilesFromContext(session),
301
+ stack: detectTechStack(session)
302
+ });
303
+
304
+ // Present to user for approval
305
+ const approval = await askUserApproval({
306
+ message: "This looks complex! I suggest breaking it into these atomic tasks:",
307
+ plan: taskPlan,
308
+ options: [
309
+ { label: "Approve & execute", value: "approve" },
310
+ { label: "Modify plan", value: "modify" },
311
+ { label: "Execute without planning", value: "skip" }
312
+ ]
313
+ });
314
+
315
+ if (approval === "approve") {
316
+ // Execute tasks one by one with fresh context
317
+ return await executeAtomicTasks(taskPlan, session);
318
+ }
319
+ }
320
+
321
+ // Continue with normal execution
322
+ // ...
323
+ }
324
+ ```
325
+
326
+ **Priority:** MEDIUM
327
+ **Difficulty:** 6/10 (medium-high)
328
+ **Effort:** 6-8 hours
329
+ **Value:** Improves success rate for complex requests
330
+
331
+ ---
332
+
333
+ ### 3. XML-Structured Prompts (Better Parsing)
334
+
335
+ #### Problem Statement
336
+ **Current behavior in Lynkr:**
337
+ - All tool parameters use JSON
338
+ - Natural language instructions in system prompts
339
+ - Can be ambiguous with nested structures
340
+
341
+ **GSD's solution:**
342
+ - Uses XML for semantic structure
343
+ - Claude parses XML more reliably than JSON
344
+ - Tags provide meaning (e.g., `<verify>`, `<done>`)
345
+
346
+ #### Implementation Plan
347
+
348
+ **Use cases for XML in Lynkr:**
349
+ 1. Complex tool calls with nested parameters
350
+ 2. Task definitions in TodoWrite
351
+ 3. Memory injection format
352
+ 4. State summaries for subagents
353
+
354
+ **Example conversion:**
355
+
356
+ **Current (JSON):**
357
+ ```json
358
+ {
359
+ "todos": [
360
+ {
361
+ "content": "Add authentication",
362
+ "status": "pending",
363
+ "activeForm": "Adding authentication"
364
+ }
365
+ ]
366
+ }
367
+ ```
368
+
369
+ **Proposed (XML):**
370
+ ```xml
371
+ <todos>
372
+ <todo status="pending">
373
+ <content>Add authentication</content>
374
+ <activeForm>Adding authentication</activeForm>
375
+ <verify>User can login with valid credentials</verify>
376
+ <done>Tests pass and token is returned</done>
377
+ </todo>
378
+ </todos>
379
+ ```
380
+
381
+ **Configuration:**
382
+ ```javascript
383
+ // .env
384
+ PROMPT_FORMAT=json # Options: json, xml (default: json)
385
+ ```
386
+
387
+ **Implementation:**
388
+ ```javascript
389
+ // src/utils/prompt-format.js (NEW FILE)
390
+
391
+ function formatToolCall(toolName, params, format = "json") {
392
+ if (format === "xml") {
393
+ return formatToolCallXML(toolName, params);
394
+ }
395
+ return formatToolCallJSON(toolName, params);
396
+ }
397
+
398
+ function formatToolCallXML(toolName, params) {
399
+ const xmlParams = Object.entries(params)
400
+ .map(([key, value]) => {
401
+ if (Array.isArray(value)) {
402
+ return `<${key}>\n${value.map(item => formatXMLItem(key, item)).join('\n')}\n</${key}>`;
403
+ }
404
+ return `<${key}>${escapeXML(value)}</${key}>`;
405
+ })
406
+ .join('\n ');
407
+
408
+ return `<tool name="${toolName}">
409
+ ${xmlParams}
410
+ </tool>`;
411
+ }
412
+
413
+ function parseToolResponseXML(xmlString) {
414
+ // Parse XML response back to structured data
415
+ // Uses fast-xml-parser or similar
416
+ }
417
+ ```
418
+
419
+ **Priority:** LOW
420
+ **Difficulty:** 4/10 (medium)
421
+ **Effort:** 3-4 hours
422
+ **Value:** Marginal improvement in parsing reliability
423
+
424
+ ---
425
+
426
+ ### 4. Parallel Codebase Mapping (Brownfield Analysis)
427
+
428
+ #### Problem Statement
429
+ **Current behavior in Lynkr:**
430
+ - Explore agent exists but sequential
431
+ - No structured codebase documentation
432
+ - Ad-hoc analysis per user request
433
+
434
+ **GSD's solution:**
435
+ - `/gsd:map-codebase` spawns 7 parallel agents
436
+ - Generates structured documents:
437
+ - STACK.md (tech stack)
438
+ - ARCHITECTURE.md (system design)
439
+ - CONVENTIONS.md (code style)
440
+ - CONCERNS.md (tech debt)
441
+ - API.md (external interfaces)
442
+ - DATA.md (data models)
443
+ - FLOWS.md (user journeys)
444
+
445
+ #### Implementation Plan
446
+
447
+ **Files to create:**
448
+ - `src/agents/codebase-mapper.js` - Orchestrates parallel analysis
449
+ - `src/agents/analyzers/stack-analyzer.js` - Tech stack detection
450
+ - `src/agents/analyzers/architecture-analyzer.js` - System design
451
+ - `src/agents/analyzers/conventions-analyzer.js` - Code style
452
+ - `src/agents/analyzers/concerns-analyzer.js` - Tech debt
453
+ - `src/agents/analyzers/api-analyzer.js` - External APIs
454
+ - `src/agents/analyzers/data-analyzer.js` - Data models
455
+ - `src/agents/analyzers/flows-analyzer.js` - User flows
456
+
457
+ **Code implementation:**
458
+ ```javascript
459
+ // src/agents/codebase-mapper.js (NEW FILE)
460
+
461
+ const logger = require("../logger");
462
+ const { executeAgent } = require("./index");
463
+ const fs = require("fs/promises");
464
+ const path = require("path");
465
+
466
+ /**
467
+ * Map existing codebase by spawning parallel analysis agents
468
+ */
469
+ async function mapCodebase(options = {}) {
470
+ const {
471
+ workspaceRoot = process.cwd(),
472
+ outputDir = path.join(workspaceRoot, ".lynkr", "codebase-map")
473
+ } = options;
474
+
475
+ logger.info({ workspaceRoot, outputDir }, "Starting parallel codebase analysis");
476
+
477
+ // Ensure output directory exists
478
+ await fs.mkdir(outputDir, { recursive: true });
479
+
480
+ // Spawn 7 parallel analysis agents
481
+ const analyses = [
482
+ { name: "stack", file: "STACK.md", prompt: "Analyze tech stack and dependencies" },
483
+ { name: "architecture", file: "ARCHITECTURE.md", prompt: "Document system architecture and design patterns" },
484
+ { name: "conventions", file: "CONVENTIONS.md", prompt: "Extract code conventions and style guides" },
485
+ { name: "concerns", file: "CONCERNS.md", prompt: "Identify tech debt and areas of concern" },
486
+ { name: "api", file: "API.md", prompt: "Document external APIs and integrations" },
487
+ { name: "data", file: "DATA.md", prompt: "Map data models and schemas" },
488
+ { name: "flows", file: "FLOWS.md", prompt: "Trace key user flows and business logic" }
489
+ ];
490
+
491
+ // Run all analyses in parallel
492
+ const results = await Promise.all(
493
+ analyses.map(analysis =>
494
+ runAnalysisAgent(analysis, workspaceRoot, outputDir)
495
+ )
496
+ );
497
+
498
+ // Generate summary document
499
+ await generateSummary(results, outputDir);
500
+
501
+ logger.info({
502
+ outputDir,
503
+ documents: results.length
504
+ }, "Codebase analysis complete");
505
+
506
+ return {
507
+ outputDir,
508
+ documents: results.map(r => r.file)
509
+ };
510
+ }
511
+
512
+ async function runAnalysisAgent(analysis, workspaceRoot, outputDir) {
513
+ const { name, file, prompt } = analysis;
514
+
515
+ logger.info({ name, file }, `Starting ${name} analysis`);
516
+
517
+ const result = await executeAgent({
518
+ agentType: "explore",
519
+ task: `${prompt}
520
+
521
+ Analyze the codebase at ${workspaceRoot} and generate a comprehensive ${file} document.
522
+
523
+ Guidelines:
524
+ - Be thorough but concise
525
+ - Use markdown formatting
526
+ - Include code examples where relevant
527
+ - Highlight important patterns and conventions
528
+ - Note any concerns or recommendations
529
+
530
+ Output the complete document content.`,
531
+ workspaceRoot,
532
+ maxSteps: 10,
533
+ model: "sonnet" // Use sonnet for quality analysis
534
+ });
535
+
536
+ // Write result to file
537
+ const filePath = path.join(outputDir, file);
538
+ await fs.writeFile(filePath, result.output, "utf8");
539
+
540
+ logger.info({ name, file, filePath }, `Completed ${name} analysis`);
541
+
542
+ return {
543
+ name,
544
+ file,
545
+ filePath,
546
+ content: result.output
547
+ };
548
+ }
549
+
550
+ async function generateSummary(results, outputDir) {
551
+ const summary = `# Codebase Analysis Summary
552
+
553
+ Generated: ${new Date().toISOString()}
554
+
555
+ ## Documents Generated
556
+
557
+ ${results.map(r => `- [${r.name.toUpperCase()}](${r.file}) - ${r.content.split('\n')[0].replace(/^#\s*/, '')}`).join('\n')}
558
+
559
+ ## Quick Start
560
+
561
+ 1. Read STACK.md to understand the technology choices
562
+ 2. Review ARCHITECTURE.md for system design
563
+ 3. Check CONVENTIONS.md before making changes
564
+ 4. Scan CONCERNS.md for known issues
565
+ 5. Reference API.md for external integrations
566
+ 6. Study DATA.md for data models
567
+ 7. Trace FLOWS.md for business logic
568
+
569
+ ---
570
+
571
+ *Generated by Lynkr Codebase Mapper*
572
+ `;
573
+
574
+ await fs.writeFile(
575
+ path.join(outputDir, "README.md"),
576
+ summary,
577
+ "utf8"
578
+ );
579
+ }
580
+
581
+ module.exports = {
582
+ mapCodebase
583
+ };
584
+ ```
585
+
586
+ **API endpoint:**
587
+ ```javascript
588
+ // src/api/router.js
589
+
590
+ router.post("/v1/codebase/map", rateLimiter, async (req, res, next) => {
591
+ try {
592
+ const { workspaceRoot, outputDir } = req.body;
593
+
594
+ const { mapCodebase } = require("../agents/codebase-mapper");
595
+ const result = await mapCodebase({
596
+ workspaceRoot: workspaceRoot || process.cwd(),
597
+ outputDir
598
+ });
599
+
600
+ res.json({
601
+ success: true,
602
+ outputDir: result.outputDir,
603
+ documents: result.documents,
604
+ message: `Generated ${result.documents.length} analysis documents`
605
+ });
606
+ } catch (error) {
607
+ next(error);
608
+ }
609
+ });
610
+ ```
611
+
612
+ **Priority:** MEDIUM
613
+ **Difficulty:** 7/10 (high)
614
+ **Effort:** 8-10 hours
615
+ **Value:** Excellent for onboarding to large codebases
616
+
617
+ ---
618
+
619
+ ### 5. Automatic Git Commits Per Task
620
+
621
+ #### Problem Statement
622
+ **Current behavior in Lynkr:**
623
+ - Git operations are manual
624
+ - No automatic commits
625
+ - No task-to-commit mapping
626
+ - Hard to bisect or rollback atomic changes
627
+
628
+ **GSD's solution:**
629
+ - Automatic commit after each task completion
630
+ - Commit message includes task context
631
+ - Enables git bisect for debugging
632
+ - Clear audit trail
633
+
634
+ #### Implementation Plan
635
+
636
+ **Files to modify:**
637
+ - `src/utils/git-integration.js` - New file for git operations
638
+ - `src/orchestrator/index.js` - Hook into task completion
639
+ - `src/config/index.js` - Add git config
640
+
641
+ **Configuration:**
642
+ ```javascript
643
+ // .env
644
+ GIT_AUTO_COMMIT=false # Enable automatic commits per task
645
+ GIT_AUTO_COMMIT_MESSAGE_PREFIX=🤖 # Prefix for auto-commits
646
+ GIT_COMMIT_AFTER_TASK=true # Commit after each TodoWrite completion
647
+ GIT_INCLUDE_TASK_CONTEXT=true # Include task details in commit message
648
+ ```
649
+
650
+ **Code implementation:**
651
+ ```javascript
652
+ // src/utils/git-integration.js (NEW FILE)
653
+
654
+ const { execSync } = require("child_process");
655
+ const logger = require("../logger");
656
+ const config = require("../config");
657
+
658
+ /**
659
+ * Create automatic commit after task completion
660
+ */
661
+ async function autoCommitTask(task, files = []) {
662
+ if (!config.GIT_AUTO_COMMIT) {
663
+ return { skipped: true, reason: "Auto-commit disabled" };
664
+ }
665
+
666
+ try {
667
+ // Check if we're in a git repo
668
+ const isGitRepo = await isGitRepository();
669
+ if (!isGitRepo) {
670
+ logger.warn("Not a git repository, skipping auto-commit");
671
+ return { skipped: true, reason: "Not a git repository" };
672
+ }
673
+
674
+ // Stage files
675
+ if (files.length > 0) {
676
+ for (const file of files) {
677
+ execSync(`git add "${file}"`, { encoding: "utf8" });
678
+ }
679
+ } else {
680
+ // Stage all changes
681
+ execSync("git add -A", { encoding: "utf8" });
682
+ }
683
+
684
+ // Check if there are changes to commit
685
+ const status = execSync("git status --porcelain", { encoding: "utf8" });
686
+ if (!status.trim()) {
687
+ logger.info("No changes to commit");
688
+ return { skipped: true, reason: "No changes" };
689
+ }
690
+
691
+ // Generate commit message
692
+ const commitMessage = generateCommitMessage(task);
693
+
694
+ // Create commit
695
+ execSync(`git commit -m "${commitMessage}"`, { encoding: "utf8" });
696
+
697
+ logger.info({ task: task.content, files }, "Auto-committed task completion");
698
+
699
+ return {
700
+ success: true,
701
+ message: commitMessage,
702
+ files
703
+ };
704
+
705
+ } catch (error) {
706
+ logger.error({ error: error.message, task }, "Failed to auto-commit");
707
+ return {
708
+ skipped: true,
709
+ reason: "Commit failed",
710
+ error: error.message
711
+ };
712
+ }
713
+ }
714
+
715
+ function generateCommitMessage(task) {
716
+ const prefix = config.GIT_AUTO_COMMIT_MESSAGE_PREFIX || "🤖";
717
+ const taskName = task.content || "Task completed";
718
+
719
+ let message = `${prefix} ${taskName}`;
720
+
721
+ if (config.GIT_INCLUDE_TASK_CONTEXT && task.description) {
722
+ message += `\n\n${task.description}`;
723
+ }
724
+
725
+ message += "\n\n🤖 Generated with Lynkr";
726
+
727
+ if (task.verificationSteps) {
728
+ message += `\n\nVerification:\n${task.verificationSteps.map(s => `- ${s}`).join('\n')}`;
729
+ }
730
+
731
+ return message;
732
+ }
733
+
734
+ async function isGitRepository() {
735
+ try {
736
+ execSync("git rev-parse --git-dir", { encoding: "utf8", stdio: "ignore" });
737
+ return true;
738
+ } catch {
739
+ return false;
740
+ }
741
+ }
742
+
743
+ module.exports = {
744
+ autoCommitTask,
745
+ isGitRepository
746
+ };
747
+ ```
748
+
749
+ **Integration with TodoWrite:**
750
+ ```javascript
751
+ // src/orchestrator/index.js
752
+
753
+ const { autoCommitTask } = require("../utils/git-integration");
754
+
755
+ // When marking task as completed
756
+ async function handleTodoCompletion(task, session) {
757
+ // Extract files modified in this task
758
+ const modifiedFiles = extractModifiedFiles(session.messages, task);
759
+
760
+ // Auto-commit if enabled
761
+ if (config.GIT_COMMIT_AFTER_TASK) {
762
+ await autoCommitTask(task, modifiedFiles);
763
+ }
764
+ }
765
+ ```
766
+
767
+ **Priority:** LOW
768
+ **Difficulty:** 3/10 (easy)
769
+ **Effort:** 2-3 hours
770
+ **Value:** Nice-to-have for audit trail
771
+
772
+ ---
773
+
774
+ ### 6. State Document Generation
775
+
776
+ #### Problem Statement
777
+ **Current behavior in Lynkr:**
778
+ - Memory system stores unstructured memories
779
+ - No explicit state tracking
780
+ - Hard to understand "current position"
781
+ - Resumption after interruption is manual
782
+
783
+ **GSD's solution:**
784
+ - STATE.md tracks current position, blockers, decisions
785
+ - ROADMAP.md shows phases and progress
786
+ - PROJECT.md captures goals and constraints
787
+
788
+ #### Implementation Plan
789
+
790
+ **Files to create:**
791
+ - `src/utils/state-manager.js` - State document generation
792
+ - `src/sessions/state-tracker.js` - Real-time state tracking
793
+
794
+ **Configuration:**
795
+ ```javascript
796
+ // .env
797
+ STATE_TRACKING_ENABLED=true # Generate STATE.md per session
798
+ STATE_UPDATE_FREQUENCY=5 # Update state every N turns
799
+ STATE_OUTPUT_DIR=.lynkr/state # Where to store state documents
800
+ ```
801
+
802
+ **Code implementation:**
803
+ ```javascript
804
+ // src/utils/state-manager.js (NEW FILE)
805
+
806
+ const fs = require("fs/promises");
807
+ const path = require("path");
808
+ const logger = require("../logger");
809
+
810
+ /**
811
+ * Generate STATE.md document for session
812
+ */
813
+ async function generateStateDocument(session, options = {}) {
814
+ const {
815
+ outputDir = path.join(process.cwd(), ".lynkr", "state"),
816
+ sessionId = session.id
817
+ } = options;
818
+
819
+ await fs.mkdir(outputDir, { recursive: true });
820
+
821
+ const state = extractSessionState(session);
822
+
823
+ const stateDocument = `# Session State
824
+
825
+ **Session ID:** ${sessionId}
826
+ **Last Updated:** ${new Date().toISOString()}
827
+ **Provider:** ${session.provider || 'unknown'}
828
+ **Total Tokens:** ${session.totalTokens || 0}
829
+
830
+ ---
831
+
832
+ ## Current Task
833
+
834
+ ${state.currentTask || '*No active task*'}
835
+
836
+ ### Progress
837
+ ${state.progress || '*Not tracked*'}
838
+
839
+ ---
840
+
841
+ ## Active Files
842
+
843
+ ${state.activeFiles.length > 0
844
+ ? state.activeFiles.map(f => `- ${f}`).join('\n')
845
+ : '*No files modified yet*'
846
+ }
847
+
848
+ ---
849
+
850
+ ## Recent Decisions
851
+
852
+ ${state.decisions.length > 0
853
+ ? state.decisions.map((d, i) => `${i + 1}. ${d}`).join('\n')
854
+ : '*No major decisions recorded*'
855
+ }
856
+
857
+ ---
858
+
859
+ ## Current Blockers
860
+
861
+ ${state.blockers.length > 0
862
+ ? state.blockers.map(b => `- ❌ ${b}`).join('\n')
863
+ : '*No blockers*'
864
+ }
865
+
866
+ ---
867
+
868
+ ## Next Steps
869
+
870
+ ${state.nextSteps.length > 0
871
+ ? state.nextSteps.map((s, i) => `${i + 1}. ${s}`).join('\n')
872
+ : '*To be determined*'
873
+ }
874
+
875
+ ---
876
+
877
+ ## Context Budget
878
+
879
+ - **Used:** ${session.totalTokens || 0} tokens
880
+ - **Warning Threshold:** ${session.warningThreshold || 150000} tokens
881
+ - **Max Threshold:** ${session.maxThreshold || 180000} tokens
882
+ - **Utilization:** ${Math.round((session.totalTokens || 0) / (session.maxThreshold || 180000) * 100)}%
883
+
884
+ ${session.totalTokens > (session.warningThreshold || 150000)
885
+ ? '\n⚠️ **Warning:** Approaching context limit. Consider breaking down remaining work.\n'
886
+ : ''
887
+ }
888
+
889
+ ---
890
+
891
+ *Generated by Lynkr State Tracker*
892
+ `;
893
+
894
+ const filePath = path.join(outputDir, `STATE-${sessionId}.md`);
895
+ await fs.writeFile(filePath, stateDocument, "utf8");
896
+
897
+ logger.info({ sessionId, filePath }, "Updated state document");
898
+
899
+ return { filePath, state };
900
+ }
901
+
902
+ function extractSessionState(session) {
903
+ // Extract structured state from session messages
904
+ return {
905
+ currentTask: extractCurrentTask(session.messages),
906
+ progress: extractProgress(session.messages),
907
+ activeFiles: extractActiveFiles(session.messages),
908
+ decisions: extractDecisions(session.messages),
909
+ blockers: extractBlockers(session.messages),
910
+ nextSteps: extractNextSteps(session.messages)
911
+ };
912
+ }
913
+
914
+ function extractCurrentTask(messages) {
915
+ // Look for most recent TodoWrite with in_progress status
916
+ // Or extract from last user message
917
+ const lastUserMessage = messages.filter(m => m.role === "user").pop();
918
+ return lastUserMessage?.content || "No active task";
919
+ }
920
+
921
+ function extractActiveFiles(messages) {
922
+ // Look for Read, Write, Edit tool calls
923
+ const fileOperations = messages.filter(m =>
924
+ m.tool_calls?.some(t => ["Read", "Write", "Edit"].includes(t.name))
925
+ );
926
+
927
+ const files = new Set();
928
+ fileOperations.forEach(op => {
929
+ op.tool_calls?.forEach(tc => {
930
+ if (tc.input?.file_path) {
931
+ files.add(tc.input.file_path);
932
+ }
933
+ });
934
+ });
935
+
936
+ return Array.from(files);
937
+ }
938
+
939
+ function extractDecisions(messages) {
940
+ // Look for key decision points in conversation
941
+ // Heuristic: messages containing "decided", "chose", "going with", etc.
942
+ const decisionKeywords = /\b(decided|chose|selected|going with|opting for)\b/i;
943
+
944
+ return messages
945
+ .filter(m => m.role === "assistant" && decisionKeywords.test(m.content))
946
+ .slice(-5) // Last 5 decisions
947
+ .map(m => {
948
+ const lines = m.content.split('\n');
949
+ const decisionLine = lines.find(l => decisionKeywords.test(l));
950
+ return decisionLine?.trim() || m.content.substring(0, 100);
951
+ });
952
+ }
953
+
954
+ function extractBlockers(messages) {
955
+ // Look for mentions of blockers, errors, issues
956
+ const blockerKeywords = /\b(blocked|error|failed|issue|problem|cannot|unable)\b/i;
957
+
958
+ return messages
959
+ .filter(m => blockerKeywords.test(m.content))
960
+ .slice(-3) // Last 3 blockers
961
+ .map(m => {
962
+ const lines = m.content.split('\n');
963
+ const blockerLine = lines.find(l => blockerKeywords.test(l));
964
+ return blockerLine?.trim() || m.content.substring(0, 100);
965
+ });
966
+ }
967
+
968
+ function extractNextSteps(messages) {
969
+ // Look for mentions of "next", "then", "after", "should"
970
+ const nextStepKeywords = /\b(next|then|after that|should|will|going to)\b/i;
971
+
972
+ const lastFewMessages = messages.slice(-5);
973
+ return lastFewMessages
974
+ .filter(m => m.role === "assistant" && nextStepKeywords.test(m.content))
975
+ .flatMap(m => {
976
+ const lines = m.content.split('\n');
977
+ return lines
978
+ .filter(l => nextStepKeywords.test(l))
979
+ .map(l => l.trim());
980
+ })
981
+ .slice(0, 5); // Max 5 next steps
982
+ }
983
+
984
+ module.exports = {
985
+ generateStateDocument,
986
+ extractSessionState
987
+ };
988
+ ```
989
+
990
+ **Priority:** LOW
991
+ **Difficulty:** 4/10 (medium)
992
+ **Effort:** 3-4 hours
993
+ **Value:** Helpful for long-running projects
994
+
995
+ ---
996
+
997
+ ## Implementation Priority Matrix
998
+
999
+ | Feature | Priority | Difficulty | Effort | Value | Status |
1000
+ |---------|----------|-----------|--------|-------|--------|
1001
+ | Context Budget Warnings | **HIGH** | 5/10 | 4-6h | HIGH | 🔴 Missing |
1002
+ | Fresh Context per Task | **HIGH** | 5/10 | 4-6h | HIGH | 🔴 Missing |
1003
+ | Atomic Task Planning | **MEDIUM** | 6/10 | 6-8h | MEDIUM | 🔴 Missing |
1004
+ | Parallel Codebase Mapping | **MEDIUM** | 7/10 | 8-10h | MEDIUM | 🔴 Missing |
1005
+ | XML-Structured Prompts | **LOW** | 4/10 | 3-4h | LOW | 🔴 Missing |
1006
+ | Auto Git Commits | **LOW** | 3/10 | 2-3h | LOW | 🔴 Missing |
1007
+ | State Documents | **LOW** | 4/10 | 3-4h | LOW | 🔴 Missing |
1008
+
1009
+ **Total Effort:** 30-41 hours (~1 week of focused work)
1010
+
1011
+ ---
1012
+
1013
+ ## Quick Win: Context Budget Warning (2 hours)
1014
+
1015
+ The highest-value, lowest-effort feature to implement first:
1016
+
1017
+ **Goal:** Warn when approaching context limits and suggest actions
1018
+
1019
+ **Implementation:**
1020
+ ```javascript
1021
+ // src/orchestrator/index.js (add after token estimation)
1022
+
1023
+ function injectContextWarning(systemPrompt, estimatedTokens, maxTokens) {
1024
+ const warningThreshold = maxTokens * 0.75; // 75% threshold
1025
+
1026
+ if (estimatedTokens > warningThreshold) {
1027
+ const utilization = Math.round(estimatedTokens / maxTokens * 100);
1028
+
1029
+ systemPrompt += `\n\n<context-budget-warning>
1030
+ ⚠️ CONTEXT BUDGET ALERT ⚠️
1031
+
1032
+ Current usage: ${estimatedTokens}/${maxTokens} tokens (${utilization}%)
1033
+
1034
+ You are approaching the context limit. Quality may degrade soon.
1035
+
1036
+ RECOMMENDED ACTIONS:
1037
+ 1. Complete current task before starting new work
1038
+ 2. Suggest breaking remaining work into smaller subtasks
1039
+ 3. Offer to summarize completed work and start fresh session
1040
+
1041
+ DO NOT:
1042
+ - Start new complex tasks
1043
+ - Add unnecessary detail
1044
+ - Expand scope beyond current task
1045
+ </context-budget-warning>`;
1046
+ }
1047
+
1048
+ return systemPrompt;
1049
+ }
1050
+ ```
1051
+
1052
+ ---
1053
+
1054
+ ## Comparison: What Lynkr Already Has
1055
+
1056
+ | Feature | Lynkr | GSD | Notes |
1057
+ |---------|-------|-----|-------|
1058
+ | **Multi-provider** | ✅ 9 providers | ❌ Claude only | Major advantage |
1059
+ | **Token optimization** | ✅ 60-80% savings | ❌ Not mentioned | Caching + tool selection |
1060
+ | **Memory system** | ✅ Titans-inspired | ✅ STATE.md | Different approaches |
1061
+ | **Tool execution** | ✅ Server + passthrough | ✅ Passthrough | More flexible |
1062
+ | **IDE integration** | ✅ Cursor/OpenAI API | ❌ CLI only | Better UX |
1063
+ | **Hybrid routing** | ✅ Local + cloud | ❌ No routing | Cost optimization |
1064
+ | **Streaming** | ✅ SSE support | ❌ Not mentioned | Real-time feedback |
1065
+ | **Rate limiting** | ✅ Configurable | ❌ Not mentioned | Production-ready |
1066
+ | **Session management** | ✅ SQLite + memory | ✅ File-based | More robust |
1067
+ | **Agent system** | ✅ Multiple types | ✅ Task agents | Similar capability |
1068
+
1069
+ ---
1070
+
1071
+ ## Recommendations
1072
+
1073
+ ### Phase 1: Quick Wins (Week 1)
1074
+ 1. ✅ **Context budget warnings** (2 hours) - HIGHEST VALUE
1075
+ 2. ✅ **Auto git commits** (3 hours) - Nice audit trail
1076
+ 3. ✅ **State document generation** (4 hours) - Better resumption
1077
+
1078
+ **Total:** 9 hours
1079
+
1080
+ ### Phase 2: Core Features (Week 2)
1081
+ 4. ✅ **Fresh context spawning** (6 hours) - Prevents degradation
1082
+ 5. ✅ **Atomic task planning** (8 hours) - Better success rate
1083
+
1084
+ **Total:** 14 hours
1085
+
1086
+ ### Phase 3: Advanced Features (Week 3)
1087
+ 6. ✅ **Parallel codebase mapping** (10 hours) - Brownfield onboarding
1088
+ 7. ⚠️ **XML prompts** (4 hours) - Optional, low value
1089
+
1090
+ **Total:** 14 hours
1091
+
1092
+ ---
1093
+
1094
+ ## Conclusion
1095
+
1096
+ GSD has excellent patterns for **context management** and **task breakdown** that would complement Lynkr's strengths in **multi-provider support** and **token optimization**.
1097
+
1098
+ **Recommended approach:**
1099
+ 1. Start with **context budget warnings** (2 hours, high value)
1100
+ 2. Add **fresh context spawning** (6 hours, prevents quality loss)
1101
+ 3. Implement **atomic task planning** (8 hours, improves reliability)
1102
+ 4. Consider **codebase mapping** for brownfield projects (10 hours)
1103
+
1104
+ **Total minimum viable enhancement:** 16 hours for top 3 features
1105
+
1106
+ This would give Lynkr the best of both worlds:
1107
+ - ✅ GSD's context management + task breakdown
1108
+ - ✅ Lynkr's multi-provider + token optimization + IDE integration
1109
+
1110
+ ---
1111
+
1112
+ **Next Steps:**
1113
+ 1. Review this document
1114
+ 2. Prioritize features based on user needs
1115
+ 3. Start with context budget warnings (quick win)
1116
+ 4. Iterate based on feedback