---
title: "File Combiner"
---

# Project: File Combiner

**Source:** `1-combind/`  
**Model:** `gemma4:26b`  
**Type:** TypeScript (Bun runtime)

## What It Does

The file combiner is the glue of our automation pipeline. It takes multiple files and wraps them in XML-like tags, producing a single output that can be fed to Ollama as context.

```
./1-combind/code -m "Fix this bug" prompt.txt error.txt code.py
```

Output:

```
<message>Fix this bug</message>
<prompt.txt>Write a bash script...</prompt.txt>
<error.txt>SyntaxError: line 42...</error.txt>
<code.py>#!/usr/bin/env python3...</code.py>
```

This is how we feed context back to the model during the self-improving loop — the original prompt, the generated code, and the error output all go in as tagged sections.

## The Prompt

```
write a standalone typescript script that has a shebang header using bun

it takes a list of files as arguments and concatenes them together marking them

example

script [-m "message"] file1 file2 file3

will output

<message>message</message>
<file1>{{contents of file1}}</file1>
<file2>{{cotents of file2}}</file2>
<file3>{{contents of file1}}</file3>

the -m message is optional

output only code
```

## The Code

```typescript
#!/usr/bin/env bun

const args = Bun.argv.slice(2);
let message = "";
const files: string[] = [];

// Parse arguments
for (let i = 0; i < args.length; i++) {
  if (args[i] === "-m" && i + 1 < args.length) {
    message = args[i + 1];
    i++; // Skip the next argument as it's the message content
  } else {
    files.push(args[i]);
  }
}

async function run() {
  // Output message if provided
  if (message) {
    console.log(`<message>${message}</message>`);
  }

  // Process each file
  for (const filePath of files) {
    try {
      const file = Bun.file(filePath);

      if (!(await file.exists())) {
        console.error(`Error: File not found: ${filePath}`);
        continue;
      }

      const content = await file.text();
      // Using the filename as the tag name
      console.log(`<${filePath}>${content}</${filePath}>`);
    } catch (error) {
      console.error(
        `Error processing ${filePath}:`,
        error instanceof Error ? error.message : error,
      );
    }
  }
}

run();
```

## How to Use

```bash
chmod +x 1-combind/code

# Combine a prompt and some files
./1-combind/code prompt.txt file1.py file2.md

# With a message
./1-combind/code -m "Here's the error" prompt.txt code.py error.txt

# Pipe directly to Ollama
./1-combind/code -m "Fix this" prompt.md code.py | ollama run gemma4:26b
```

## The Test

The test file demonstrates the `-m` flag:

```bash
#!/bin/bash
./1-combind/code -m "This is a message" 0-weather/prompt.md
```

Expected output:

```
<message>This is a message</message>
<0-weather/prompt.md>write a bash script that uses wget to get the weather in new york city</0-weather/prompt.md>
```

## Key Lessons

- **Bun for TypeScript.** The model chose Bun runtime for its simple file I/O (`Bun.file(path).text()`).
- **Tagging provides structure.** The XML-like tags (`<filename>content</filename>`) give the model clear boundaries between different pieces of context.
- **The `-m` flag is the channel.** It provides human intent ("Fix this bug") alongside raw file contents.
- **This is the feedback pipe.** In our self-improving loop, this tool packs prompt + code + error into one message for the model.

**Next: [Data Extractor →](/run-ai-locally/projects/data-extractor/)**
