SkillAgentSearch skills...

llm-loop

Versatile Almost Local, Eventually Reasonable Assistant πŸ”«

Install / Use

npx skills add vakovalskii/NeuralDeskApp

Installs into whichever agent you are using.

About this skill
πŸ“

Cursor Rules

Cursor IDE rules (v2)

Quality Score

67/100

Supported Platforms

Cursor

Our assessment of llm-loop

llm-loop scores 67/100 on our quality scale, 890th of 941 AI & Machine Learning skills we index.

Its Cursor Rules is 6.2 KB long, well organised into 15 sections with 10 code examples: a thorough specification that gives an agent plenty to work with.

It has no GitHub stars yet, so there is no community track record; judge it on its content.

Substance
29/30
Structure
20/20
Description
8/15
Adoption
0/20
Freshness
11/15

Maintenance, license and trust

  • The repository was last updated about 5 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
  • Our last check on 2026-10-19 found the source still online.
  • No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
  • Its trust signals score 78/100, with 2 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit β€” read the skill file before letting an agent act on it.

Safety scan

No issues found

Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.

AI review by kimi-k2.7-code on 2026-09-24. Automated pattern scan on 2026-09-24. It catches known dangerous patterns, not every risk β€” read a skill before letting an agent act on it.

llm-loop compared with similar skills

All 4 of these similar skills score higher than llm-loop; compare them before choosing.

SkillScoreStarsUpdatedFormat
llm-loop (this skill)by vakovalskii6705mo agoCursor Rules
claude-memby thedotmack100102.4ktodayCLAUDE.md
Understand-Anythingby Egonex-AI10087.8ktodayCLAUDE.md
headroomby headroomlabs-ai10077.6ktodayCLAUDE.md
CowAgentby zhayujie10047.5ktodayCLAUDE.md

Frequently asked questions

How do I install llm-loop?
Run npx skills add vakovalskii/NeuralDeskApp. The install tabs above show the steps for each supported agent.
Which AI agents does llm-loop work with?
It is written for Cursor, as a Cursor Rules file. Other agents that read the same format can often use it too.
Is llm-loop safe to use?
Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It declares no license and scores 78/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is llm-loop still maintained?
The repository was last updated about 5 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.

LLM Agent Loop

Overview

The agent loop in runner-openai.ts implements a ReAct-style agent that can:

  1. Receive user messages
  2. Stream LLM responses
  3. Execute tools
  4. Continue until task completion

Loop Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Agent Loop                      β”‚
β”‚                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Build   │───►│  Call    │───►│  Stream  β”‚  β”‚
β”‚  β”‚ Messages β”‚    β”‚   LLM    β”‚    β”‚ Response β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚       β–²                               β”‚         β”‚
β”‚       β”‚                               β–Ό         β”‚
β”‚       β”‚                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚       β”‚         No             β”‚  Tool    β”‚    β”‚
β”‚       └────────────────────────│  Calls?  β”‚    β”‚
β”‚                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                      β”‚ Yes     β”‚
β”‚                                      β–Ό         β”‚
β”‚                               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚                               β”‚ Execute  β”‚     β”‚
β”‚                               β”‚  Tools   β”‚     β”‚
β”‚                               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                                      β”‚         β”‚
β”‚                                      β–Ό         β”‚
β”‚                               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚                               β”‚   Add    β”‚     β”‚
β”‚                               β”‚ Results  β”‚β”€β”€β”€β”€β”€β”˜
β”‚                               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components

Message Array

OpenAI chat format:

type ChatMessage = {
  role: 'system' | 'user' | 'assistant' | 'tool';
  content: string | ContentPart[];
  tool_calls?: ToolCall[];      // Only for assistant
  tool_call_id?: string;        // Only for tool
  name?: string;                // Tool name for tool messages
};

Streaming

Uses OpenAI SDK streaming with requestAnimationFrame throttling:

const stream = await client.chat.completions.create({
  model: modelName,
  messages: messages,
  tools: activeTools,
  stream: true,
  stream_options: { include_usage: true }
});

for await (const chunk of stream) {
  // Process delta content
  if (chunk.choices[0]?.delta?.content) {
    sendStreamEvent(chunk.choices[0].delta.content);
  }
  
  // Accumulate tool calls
  if (chunk.choices[0]?.delta?.tool_calls) {
    accumulateToolCalls(chunk.choices[0].delta.tool_calls);
  }
}

Tool Execution Flow

// 1. Check permission mode
const permissionMode = settings?.permissionMode || 'ask';

if (permissionMode === 'ask') {
  // 2. Send permission request to UI
  sendPermissionRequest(toolUseId, toolName, toolArgs);
  
  // 3. Wait for user response
  const approved = await waitForPermission(toolUseId);
  if (!approved) continue;
}

// 4. Execute tool
const result = await toolExecutor.executeTool(toolName, toolArgs, {
  sessionId: session.id,
  onTodosChanged: (todos) => {
    // Persist and notify UI
  }
});

// 5. Add result to messages
messages.push({
  role: 'tool',
  tool_call_id: toolCall.id,
  name: toolName,
  content: result.success ? result.output : `Error: ${result.error}`
});

Loop Detection

Prevents infinite loops when model repeatedly calls same tool:

const LOOP_THRESHOLD = 5;      // Same tool N times = loop
const MAX_LOOP_RETRIES = 5;    // Max attempts to break loop

// Track recent tool calls
recentToolCalls.push({ name: toolName, args: argsString });

// Check for loops
if (recentToolCalls.length >= LOOP_THRESHOLD) {
  const lastCalls = recentToolCalls.slice(-LOOP_THRESHOLD);
  const allSameTool = lastCalls.every(c => c.name === lastCalls[0].name);
  
  if (allSameTool) {
    loopRetryCount++;
    
    if (loopRetryCount >= MAX_LOOP_RETRIES) {
      // Stop with error
      sendLoopError(toolName);
      return;
    }
    
    // Add hint to help model break loop
    messages.push({
      role: 'user',
      content: '⚠️ You are stuck in a loop. Try a different approach.'
    });
  }
}

Error Handling

Retryable Errors

Network errors are automatically retried:

const isRetryableNetworkError = (error: unknown): boolean => {
  const code = error.cause?.code;
  const status = error.status;
  
  // Retry on socket errors
  if (['ECONNRESET', 'ETIMEDOUT', 'ECONNREFUSED'].includes(code)) {
    return true;
  }
  
  // Retry on server errors
  if ([429, 500, 502, 503, 504].includes(status)) {
    return true;
  }
  
  return false;
};

Retry Logic

const MAX_STREAM_RETRIES = 3;
const RETRY_BASE_DELAY_MS = 500;

for (let attempt = 0; attempt <= MAX_STREAM_RETRIES; attempt++) {
  try {
    return await streamResponse();
  } catch (error) {
    if (!isRetryableNetworkError(error) || attempt === MAX_STREAM_RETRIES) {
      throw error;
    }
    
    const delayMs = RETRY_BASE_DELAY_MS * 2 ** attempt;
    await sleep(delayMs);
  }
}

Session Logging

Each turn is logged to ~/.localdesk/logs/sessions/{sessionId}/:

turn-001-request.json   # Full request (messages, tools, params)
turn-001-response.json  # Full response (content, tool_calls, usage)
turn-002-request.json
turn-002-response.json
...

Token Tracking

Accumulated across all iterations:

if (streamMetadata.usage) {
  totalInputTokens += streamMetadata.usage.prompt_tokens || 0;
  totalOutputTokens += streamMetadata.usage.completion_tokens || 0;
}

// Final report
sendMessage('result', {
  usage: {
    input_tokens: tota…[redacted],
    output_tokens: tota…[redacted]
  }
});

Abort Handling

User can stop generation at any point:

let aborted = false;

return {
  abort: () => {
    aborted = true;
    console.log('[OpenAI Runner] Aborted');
  }
};

// Check in loop
while (!aborted && iterationCount < MAX_ITERATIONS) {
  // ... streaming
  if (aborted) break;
  
  // ... tool execution
  if (aborted) break;
}

Configuration

| Setting | Default | Description | |---------|---------|-------------| | MAX_ITERATIONS | 50 | Max agent loop cycles | | REQUEST_TIMEOUT_MS | 5 min | LLM request timeout | | MAX_STREAM_RETRIES | 3 | Network error retries | | LOOP_THRESHOLD | 5 | Tool calls to detect loop |

Related Skills

View on GitHub
GitHub Stars0
CategoryAI
Updated5mo ago
Forks0

Trust signals

78/100

From repository metadata: license, adoption, age and documentation. Not a code audit β€” see the Safety scan above for what the skill file itself contains.

1 medium1 low1 info