# Project export: zyzx

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: TreeHacks 2024
- Tagline: A private, personalized copilot for your terminal that feels great to use.
- Devpost: https://devpost.com/software/zyzx
- GitHub: http://github.com/tam-albert/zyzx
- Demo: https://zyzx.vercel.app/
- Team: 3 GitHub contributor(s) — Albert Tam (34 commits), andrew (24 commits), Richard Chen (13 commits)

## Devpost submission (written by the team)

### Inspiration

AI-powered tools are changing the way developers think about programming incredibly quickly. Less than two years after its official launch, Copilot's become integral to the programming experience—for its users, over half of the code they write is generated by Copilot. But the terminal, another key component of the developer experience, has remained largely untouched. We found ourselves frustrated with having to constantly switch back and forth being ChatGPT sessions and terminal windows, trying to find the right context to paste in, and still needing to resort to documentation and manpages to debug unfamiliar commands. Beyond that, we wanted a private, personalized solution—one that could learn from our commands, be as "terminal-literate" as possible, and didn't rely on closed models like OpenAI's. We wanted a copilot that (1) integrated directly into the terminal, with UX as seamless as possible, (2) could learn from our commands and become a personalized assistant, and (3) worked offline and open-source, unlike most of the proprietary, closed solutions that are widespread today. So we built zyzx, a copilot that does just that.

### What it does

zyzx works as a tiny executable that you can invoke right from your shell

### How we built it

We built it in Zig!

### Challenges we ran into

We ran into many challenges; this was our first time working with the language Zig, and we also ran into many challenges training the model.

### Accomplishments we're proud of

We are proud that we have a functional terminal!

### What we learned

We learned a lot about compile time optimization and Zig.

### What's next

More commands!

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 16 recognized source files, 40 KB.
- CSS (language) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- Python (language) — detected in the code
- PyTorch (technology) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code

## Codebase structure (from repository index)

### Files (36 of 36)

```
.gitignore
build.zig
data/0to1.py
data/0to156.py
data/1to2.py
data/1to256.py
data/all_commands.txt
data/data.csv
data/evaluate.py
data/filterhistory.py
data/generate_data.py
data/labeledData.csv
data/metric.py
data/mistraldata.csv
data/performance.py
data/rcommands1.txt
data/requirements.txt
data/translate.py
model/mistral-finetune.ipynb
src/llm_client.zig
src/long_prompt.txt
src/main.zig
src/openai_agent.zig
src/openai_prompts.zig
src/prompt_examples.txt
website/.eslintrc.json
website/.gitignore
website/next.config.mjs
website/package.json
website/README.md
website/src/app/details/page.tsx
website/src/app/globals.css
website/src/app/layout.tsx
website/src/app/page.module.css
website/src/app/page.tsx
website/tsconfig.json
```

### Dependencies

- data/requirements.txt: idna@==3.6, Jinja2@==3.1.3, MarkupSafe@==2.1.5, mlx@==0.3.0, mpmath@==1.3.0, multidict@==6.0.5, networkx@==3.2.1, numpy@==1.26.4, openai@==1.12.0, pydantic@==2.6.1, pydantic_core@==2.16.2, requests@==2.31.0, sentencepiece@==0.1.99, sniffio@==1.3.0, sympy@==1.12, torch@==2.2.0, tqdm@==4.66.2, typing_extensions@==4.9.0, urllib3@==2.2.0, yarl@==1.9.4
- website/package.json: @nextui-org/react@^2.2.9, @types/node@^20, @types/react@^18, @types/react-dom@^18, @types/react-katex@^3.0.4, eslint@^8, eslint-config-next@14.1.0, next@14.1.0, react@^18, react-dom@^18, react-icon@^1.0.0, react-icons@^5.0.1, react-katex@^3.0.1, react-latex-next@^2.2.0, react-router-dom@^6.22.1, typescript@^5

### Recent commits (newest first)

- small corrections
- update results image
- fix next build errors
- write up mistral vs gpt results
- mistral does better than openai!
- responsive ui
- fix evaluation script
- update metadata
- Merge remote-tracking branch 'refs/remotes/origin/main'
- bugfixes
- add mistral model code
- final bugfixes
- Merge remote-tracking branch 'refs/remotes/origin/main'
- mixtral endpoint
- Merge branch 'main' of github.com:tam-albert/copilot
- flags
- why no double quotes lmao
- build doesn't let you have apostrophes?
- remove TODO
- rename project from copilot

## Key source files (fetched from GitHub, selected and truncated for size)

### data/requirements.txt

```
idna==3.6
Jinja2==3.1.3
MarkupSafe==2.1.5
mlx==0.3.0
mpmath==1.3.0
multidict==6.0.5
networkx==3.2.1
numpy==1.26.4
openai==1.12.0
pydantic==2.6.1
pydantic_core==2.16.2
requests==2.31.0
sentencepiece==0.1.99
sniffio==1.3.0
sympy==1.12
torch==2.2.0
tqdm==4.66.2
typing_extensions==4.9.0
urllib3==2.2.0
yarl==1.9.4

```

### website/package.json

```
{
  "name": "zyzx",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@nextui-org/react": "^2.2.9",
    "next": "14.1.0",
    "react": "^18",
    "react-dom": "^18",
    "react-icon": "^1.0.0",
    "react-icons": "^5.0.1",
    "react-katex": "^3.0.1",
    "react-latex-next": "^2.2.0",
    "react-router-dom": "^6.22.1"
  },
  "devDependencies": {
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "@types/react-katex": "^3.0.4",
    "eslint": "^8",
    "eslint-config-next": "14.1.0",
    "typescript": "^5"
  }
}

```

### website/src/app/layout.tsx

```typescript
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Zyzx | Natural Language Terminal",
  description:
    "Zyzx is a natural language terminal that supercharges your development workflow. Powered by AI that is offline, safe, and secure.",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  );
}

```

### website/src/app/page.tsx

```typescript
"use client";

import classes from "./page.module.css";

export default function Home() {
  return (
    <main className={classes.main}>
      <div className={`${classes.flex} ${classes.titleContainer}`}>
        <div className={`${classes.title} ${classes.animate}`}>
          Talk to your terminal{" "}
          <div className={classes.gradientText}>in Plain English.</div>
        </div>
        <div className={`${classes.subTitle} ${classes.animate}`}>
          Natural language queries that supercharge your development workflow.
          Powered by AI that is offline, safe, and secure.
        </div>
        <div className={`${classes.buttonContainer} ${classes.animate}`}>
          <button
            onClick={() => {
              window.location.href = "https://github.com/tam-albert/zyzx";
            }}
            className={classes.githubButton}
            style={{
              display: "flex",
              alignItems: "center",
            }}
          >
            <img
              src="/images/github.svg"
              alt="GitHub"
              style={{
                width: "30px",
                background: "white",
              }}
            />
            <div className={`${classes.black} ${classes.ml}`}>GitHub</div>
          </button>
          <button
            onClick={() => {
              window.location.replace("/details");
            }}
            className={classes.githubButton}
            style={{
              display: "flex",
              alignItems: "center",
            }}
          >
            <img
              src="/images/info.svg"
              style={{
                width: "30px",
                backgroundColor: "white",
              }}
            />
            <div className={`${classes.black} ${classes.ml}`}>Details</div>
          </button>
        </div>
        <img
          src={"/images/terminal.png"}
          alt="terminal"
          className={`${classes.terminal} ${classes.animate} ${classes.blogImage}`}
        />
      </div>
    </main>
  );
}

```

### website/src/app/details/page.tsx

```typescript
"use client";

import classes from "../page.module.css";
import "katex/dist/katex.min.css";
import { InlineMath, BlockMath } from "react-katex";

export default function Home() {
  return (
    <main className={classes.main}>
      <div className={classes.implementationFlexContainer}>
        <div className={classes.implementationContainer}>
          <div className={`${classes.flex} ${classes.titleContainer}`}>
            <div className={`${classes.title}`}>Implementation Details</div>
            <div className={`${classes.buttonContainer}`}>
              <button
                className={classes.githubButton}
                onClick={() => {
                  window.location.replace("/");
                }}
              >
                <div className={`${classes.black}`}>Back</div>
              </button>
            </div>
          </div>
          <div className={`${classes.blogContent}`}>
            <div className={`${classes.flex}`}>
              <img
                src="/images/terminal.png"
                alt="term"
                width={700}
                className={classes.blogImage}
              ></img>
            </div>
            <p>
              Our goal with this project was to address the issue of a lack of a
              reliable GitHub copilot-like assistant in the terminal. We know
              that alternatives exist, but most are not open-source or run on
              the cloud. Our vision was an agent that could be run locally, and
              hence safely, while not sacrificing its ability to be a genuinely
              useful tool.
            </p>
            <h1>Stack</h1>
            <p>
              Our entire interface was implemented in Zig. This was a new
              experience for all of us—none of us had ever written a project of
              Zig before—but we were drawn to Zig for several reasons:
            </p>
            <ul>
              <li>
                <span className={`${classes.bold}`}>
                  Faster tooling and development, compared to C/C++.
                </span>{" "}
                Building our project on Zig was incredibly smooth; despite the
                language&apos;s relatively new status, its build ecosystem,
                language server, and more felt mature and did not become pain
                points during our project.
              </li>
              <li>
                <span className={`${classes.bold}`}>
                  Performance and safety.
                </span>{" "}
                Zig&apos;s performance and safety features were a big draw for
                us. We wanted to build a tool that was fast and safe, and Zig
                seemed like the perfect fit for this.
              </li>
              <li>
                <span className={`${classes.bold}`}>
                  As an extra challenge.
                </span>{" "}
                We also wanted to learn a new language! In the end, our team
                learned a lot by implementing server-sent events parsing from
                scratch, wrangling with different terminal emulators in a new
                language, and more.
              </li>
            </ul>
            <h1>Model</h1>
            <p>
              The LLM behind the scenes is a heavily fine-tuned Mistral
              AI&apos;s Mixtral 8x7B mixture of experts model. We chose to focus
              on this model because it is well known to be one the best, if not
              the best, generally capable models for its size.
            </p>
            <p>
              Our fine-tuning process was split into two stages. During the
              first stage, we fine tuned on{" "}
              <a
                href="https://arxiv.org/abs/1802.08979"
                target="_blank"
                rel="noreferrer"
              >
                NL2Bash
              </a>
              , a dataset of roughly 10k bash commands paired with a natural
              language description of each command.
            </p>
            <div className={classes.flex}>
              <div className={classes.flex}>
                <img
                  src="/images/1to2.png"
                  width={600}
                  className={classes.blogImage}
                />
                <i>Fig 1. First stage of fine-tuning</i>
              </div>
              <div className={classes.flex}>
                <img
                  src="/images/2to3.png"
                  width={600}
                  style={{ marginTop: "3rem" }}
                  className={classes.blogImage}
                />
                <i style={{ marginBottom: "2rem" }}>
                  Fig 2. Second stage of fine-tuning
                </i>
              </div>
            </div>
            <p className={classes.mt}>
              The results from the first stage of fine-tuning led us to believe
              that we could further improve performance with another round of
              fine-tuning. We did not have more data, so we decided to generate
              more synthetically. We concatenated together and sanitized our
              .zsh history files and used this as a &quot;high-quality&quot;
              dataset. Every single command (roughly 200) was verified by human,
              so we knew that this set of data was a good starting point for
              generating data. In conjunction with examples from the original
              training set, we fed these into GPT to generate synthetic labels,
              and also entirely new synthetic pairs of data. The result was a
              synthetic dataset of around 10k more pairs of bash commands and
              their natural language counterparts.
            </p>
            <div className={classes.flex}>
              <img
                src="/images/pipeline.png"
                width={600}
                className={classes.blogImage}
              ></img>
              <i>Fig 3. Fine-
[truncated — 6775 more characters]
```

### data/1to256.py

```python
import matplotlib.pyplot as plt

# Input data
# step, training loss, validation loss
data = """25	2.857500	1.846487
50	1.076200	1.102981
75	0.760000	0.807342
100	0.623100	4.800373
125	0.871900	0.694432
150	0.514400	0.643339
175	0.560900	0.641982
200	0.488400	0.624331
225	0.435600	0.637454
250	0.579700	0.582857
275	0.579100	0.765172
300	0.743100	0.798714
325	0.605900	0.750567"""

# Parsing the data
lines = data.split("\n")
x = []
train_loss = []
validation_loss = []
for line in lines:
    parts = line.split()
    x.append(float(parts[0]))
    train_loss.append(float(parts[1]))
    validation_loss.append(float(parts[2]))

# Plotting
plt.plot(x, train_loss, label="training")
plt.plot(x, validation_loss, label="validation")
plt.xlabel("step")
plt.ylabel("loss")
plt.title("loss vs. time")
plt.legend()
plt.show()

```

### data/translate.py

```python
import json
import random

with open("all.cm", "r") as file:
    cm_file_content = file.read().splitlines()

with open("all.nl", "r") as file:
    nl_file_content = file.read().splitlines()

assert len(cm_file_content) == len(nl_file_content)

lines = [(nl, cm) for nl, cm in zip(nl_file_content, cm_file_content)]
random.shuffle(lines)

with open("training.jsonl", "w") as output_file:
    for i in range(len(lines))[:-1000]:
        json_line = {
            "input": lines[i][0].strip(),
            "output": lines[i][1].strip(),
        }
        output_file.write(json.dumps(json_line) + "\n")

with open("validation.jsonl", "w") as output_file:
    for i in range(len(lines))[-1000:]:
        json_line = {
            "input": lines[i][0].strip(),
            "output": lines[i][1].strip(),
        }
        output_file.write(json.dumps(json_line) + "\n")

```

### data/0to1.py

```python
import matplotlib.pyplot as plt

# Input data
# step, training loss, validation loss
data = """25	2.821300	2.061742
50	1.845900	1.642996
75	1.548000	1.514281
100	1.463700	1.491024
125	1.552500	1.476754
150	1.451400	1.448805
175	1.419700	1.434840
200	1.416300	1.425210
225	1.414000	1.412485
250	1.361900	1.402501
275	1.414600	1.396014
300	1.327900	1.387997
325	1.283100	1.380778
350	1.354500	1.376001
375	1.355500	1.371205
400	1.393300	1.366162
425	1.304300	1.362402
450	1.329700	1.360121
475	1.311100	1.357845
500	1.302000	1.357235"""

# Parsing the data
lines = data.split("\n")
x = []
train_loss = []
validation_loss = []
for line in lines:
    parts = line.split()
    x.append(float(parts[0]))
    train_loss.append(float(parts[1]))
    validation_loss.append(float(parts[2]))

# Plotting
plt.plot(x, train_loss, label="training")
plt.plot(x, validation_loss, label="validation")
plt.xlabel("step")
plt.ylabel("loss")
plt.title("loss vs. time")
plt.legend()
plt.show()

```

### data/0to156.py

```python
import matplotlib.pyplot as plt

# Input data
# step, training loss, validation loss
data = """25	5.035200	3.357117
50	2.426500	2.163045
75	1.881300	1.906301
100	1.705000	1.840497
125	1.749700	1.781841
150	1.694200	1.720023
175	1.705500	1.661713
200	1.546200	1.628291
225	1.433000	1.595461
250	1.434700	1.606259
275	1.591000	1.611188
300	1.456900	1.621007
325	1.440100	1.624845
350	1.529800	1.631292
375	1.515300	1.624045
400	1.539300	1.601408
425	1.586000	1.601496
450	1.580900	1.587659
475	1.432700	1.591756
500	1.471800	1.596105"""

# Parsing the data
lines = data.split("\n")
x = []
train_loss = []
validation_loss = []
for line in lines:
    parts = line.split()
    x.append(float(parts[0]))
    train_loss.append(float(parts[1]))
    validation_loss.append(float(parts[2]))

# Plotting
plt.plot(x, train_loss, label="training")
plt.plot(x, validation_loss, label="validation")
plt.xlabel("step")
plt.ylabel("loss")
plt.title("loss vs. time")
plt.legend()
plt.show()

```

### data/1to2.py

```python
import matplotlib.pyplot as plt

# Input data
# step, training loss, validation loss
data = """25	0.883400	0.599057
50	0.421700	0.539420
75	0.423600	0.530077
100	0.388300	0.528256
125	0.400200	0.519189
150	0.376300	0.516060
175	0.424800	0.507626
200	0.348600	0.509248
225	0.332400	0.510548
250	0.436100	0.499821
275	0.350900	0.498529
300	0.394900	0.495433
325	0.378800	0.492662
350	0.338900	0.491605
375	0.346600	0.487182
400	0.305400	0.497817
425	0.370800	0.483945
450	0.360500	0.483451
475	0.359300	0.479073
500	0.312400	0.484038
525	0.386800	0.477243
550	0.326500	0.475880
575	0.336400	0.476866
600	0.385400	0.477436
625	0.387200	0.470892
650	0.376300	0.469085
675	0.378300	0.467570
700	0.323300	0.467654
725	0.392700	0.464648
750	0.394000	0.464032
775	0.386900	0.461801
800	0.341300	0.461480
825	0.311400	0.461652
850	0.359800	0.461940
875	0.310900	0.461809
900	0.309300	0.460310
925	0.349200	0.459634
950	0.344100	0.459545
975	0.325800	0.459053
1000	0.260700	0.459125"""

# Parsing the data
lines = data.split("\n")
x = []
train_loss = []
validation_loss = []
for line in lines:
    parts = line.split()
    x.append(float(parts[0]))
    train_loss.append(float(parts[1]))
    validation_loss.append(float(parts[2]))

# Plotting
plt.plot(x, train_loss, label="training")
plt.plot(x, validation_loss, label="validation")
plt.xlabel("step")
plt.ylabel("loss")
plt.title("loss vs. time")
plt.legend()
plt.show()

```

[7 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]