> ## Documentation Index
> Fetch the complete documentation index at: https://docs.idyllic.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Code Reviewer

> Build a code review tool with parallel streaming outputs

# Code Reviewer

A code review tool that produces three outputs simultaneously: issues, suggestions, and refactored code. All three stream in parallel—users see all panels filling at the same time, with updates interleaving as each LLM generates tokens.

## Server Code

```typescript theme={null}
import { AgenticSystem, field, action, stream } from 'idyllic';

export default class CodeReviewer extends AgenticSystem {
  @field code = '';
  @field language = 'typescript';
  @field issues = stream<string>('');
  @field suggestions = stream<string>('');
  @field improved = stream<string>('');
  @field status: 'idle' | 'reviewing' = 'idle';

  @action()
  async setCode(code: string, language?: string) {
    this.code = code;
    if (language) this.language = language;
  }

  @action()
  async review() {
    this.status = 'reviewing';
    this.issues.reset();
    this.suggestions.reset();
    this.improved.reset();

    await Promise.all([
      this.findIssues(),
      this.generateSuggestions(),
      this.improveCode(),
    ]);

    this.status = 'idle';
  }

  private async findIssues() {
    for await (const chunk of ai.stream(
      `List issues in this ${this.language} code:\n\n${this.code}`
    )) {
      this.issues.append(chunk);
    }
    this.issues.complete();
  }

  private async generateSuggestions() {
    for await (const chunk of ai.stream(
      `Suggest improvements for this ${this.language} code:\n\n${this.code}`
    )) {
      this.suggestions.append(chunk);
    }
    this.suggestions.complete();
  }

  private async improveCode() {
    for await (const chunk of ai.stream(
      `Refactor this ${this.language} code with best practices:\n\n${this.code}`
    )) {
      this.improved.append(chunk);
    }
    this.improved.complete();
  }
}
```

The `review` action runs three streaming methods concurrently with `Promise.all`. Each method appends to its own stream. The framework multiplexes these updates over the single WebSocket connection.

The private methods don't have `@action()`, so clients can't call them directly. Only `setCode` and `review` are exposed.

## Client Code

```tsx theme={null}
import { useSystem } from '@idyllic/react';
import type { CodeReviewer } from '../systems/CodeReviewer';

export default function ReviewerUI() {
  const { code, language, issues, suggestions, improved, status, setCode, review } = useSystem<CodeReviewer>();
  const isReviewing = status === 'reviewing';

  return (
    <div className="flex flex-col h-screen p-4">
      <div className="mb-4">
        <div className="flex gap-2 mb-2">
          <select
            value={language}
            onChange={e => setCode(code, e.target.value)}
            className="px-3 py-2 border rounded"
          >
            <option value="typescript">TypeScript</option>
            <option value="python">Python</option>
            <option value="go">Go</option>
          </select>
          <button
            onClick={review}
            disabled={isReviewing || !code}
            className="px-4 py-2 bg-blue-600 text-white rounded disabled:opacity-50"
          >
            {isReviewing ? 'Reviewing...' : 'Review Code'}
          </button>
        </div>
        <textarea
          value={code}
          onChange={e => setCode(e.target.value)}
          className="w-full h-48 p-3 border rounded font-mono text-sm"
          placeholder="Paste your code here..."
        />
      </div>

      <div className="flex-1 grid grid-cols-3 gap-4">
        <Panel title="Issues" content={issues.current} streaming={isReviewing} />
        <Panel title="Suggestions" content={suggestions.current} streaming={isReviewing} />
        <Panel title="Improved" content={improved.current} streaming={isReviewing} mono />
      </div>
    </div>
  );
}

function Panel({ title, content, streaming, mono }: {
  title: string; content: string; streaming: boolean; mono?: boolean;
}) {
  return (
    <div className="flex flex-col border rounded">
      <h3 className="px-3 py-2 bg-gray-100 font-medium border-b">{title}</h3>
      <div className={`flex-1 p-3 overflow-auto whitespace-pre-wrap ${mono ? 'font-mono text-sm' : ''}`}>
        {content}
        {streaming && <span className="animate-pulse">|</span>}
      </div>
    </div>
  );
}
```

## Running the Example

```bash theme={null}
npx idyllic dev
```

Paste code with obvious issues. Click Review. All three panels fill simultaneously—Issues typically finishes first, Improved takes longest. Each cursor disappears as its stream completes.

## Why Parallel Streaming Matters

Without a framework, building this requires substantial infrastructure: WebSocket multiplexing to route interleaved updates, client-side routing to the correct UI components.

With Idyllic: define streaming fields, run concurrent async methods, let the framework handle multiplexing. The complexity of parallel streams never leaks into your code.
