All examples

JETTSON.DEV · EXAMPLE

GitHub PR Reviewer

This agent runs on 80 lines of instructions.

Given a GitHub PR URL, the agent fetches the diff, recalls your team's previously-flagged preferences, runs a senior-eye review, leaves inline comments, and writes new memories for every category it surfaces. After ~10 PRs it stops re-flagging things the senior reviewer has already accepted.

Who needs this — Engineering teams of 5-50 where a senior reviewer keeps writing 'use early returns' for the eighth time.

HOW IT WORKS

Memory in. Work. Memory out.

Every Jettson agent follows the same shape — and these steps map 1:1 to the lines in the prompt below.

  1. 1

    Reads the team's coding_standards memory namespace

  2. 2

    Fetches the PR diff via GitHub's API

  3. 3

    Reviews inline, categorizing findings: bug / security / perf / style / nit

  4. 4

    Posts a single review with line-anchored comments back to the PR

  5. 5

    Writes (or reinforces) one memory per new pattern surfaced

  6. 6

    Returns a JSON summary of categories and memory writes

RUN IT

Bring the agent online.

Get an API key from /console/api-keys, set any optional env vars below, then run the script.

run.sh
#!/usr/bin/env bash
# Spawn the GitHub PR Reviewer against the production Jettson API.
# Use ./run-local.sh while developing — same script, dev URL.
set -euo pipefail

API_KEY="${JETTSON_API_KEY:?Set JETTSON_API_KEY — get one at https://jettson.dev/console/api-keys}"
PR="${PR_URL:?Set PR_URL — e.g. https://github.com/your-org/your-repo/pull/123}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Inline ${PR_URL} into the prompt so the agent knows which PR to review.
TASK=$(sed "s|\${PR_URL}|$PR|g" "$SCRIPT_DIR/agent.md")

response=$(curl -sS -X POST https://jettson.dev/api/v1/agents \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  --data "$(jq -n --arg task "$TASK" '{ task: $task, name: "PR Reviewer" }')")

echo "$response" | jq

agent_id=$(printf '%s' "$response" | jq -r '.agent_id // empty')
if [ -n "$agent_id" ]; then
    echo
    echo "Watch progress: https://jettson.dev/console/agents/$agent_id"
fi
.env.example
# Required — your Jettson API key.
JETTSON_API_KEY=jett_sk_live_...

# Required — the PR you want reviewed.
PR_URL=https://github.com/your-org/your-repo/pull/123

# Optional — GitHub PAT (or fine-grained token) with read access to the
# repo and write access to PR reviews. If unset, the agent will read
# public-repo diffs but skip posting the review back to GitHub.
GITHUB_TOKEN=ghp_...

THE PROMPT

What the model sees.

This is the entire task prompt — no orchestration code, no glue. Edit it to fit your house style.

agent.md
You are the team's first-pass PR reviewer. The senior engineer will look at your review and either approve or push back — your job is to make their pass faster by surfacing the things they always flag.

## Step 1 — Recall the team's standards

Call `jettson_memory_search`:

- query: "code review preferences, coding standards, patterns to flag"
- namespace: "coding_standards"
- limit: 15

These memories are house rules. Treat them as authoritative over your defaults — if memory says "the team uses .then() chains intentionally", do NOT flag .then().

If memory is empty, you're on a first-run baseline: apply sensible defaults but write thorough memories at the end so the next run is informed.

## Step 2 — Fetch the PR

The PR URL is in the task as `${PR_URL}`. Parse it into `{ owner, repo, pull_number }`.

Get the PR metadata:
- `jettson_http_request` GET `https://api.github.com/repos/${owner}/${repo}/pulls/${pull_number}`
- Header: `Authorization: token ${GITHUB_TOKEN}` if set
- Header: `Accept: application/vnd.github.v3+json`

Then get the diff content:
- `jettson_http_request` GET the same URL with header `Accept: application/vnd.github.v3.diff`

If `GITHUB_TOKEN` is missing, public repos still work — note that in your final output.

## Step 3 — Review pass

Walk the diff. For each finding, categorize into exactly one of:

- **bug** — actual incorrectness (off-by-one, nullability, race, wrong error path)
- **security** — auth, injection, secret handling, SSRF, XSS
- **perf** — accidental O(n²), unbatched I/O, blocking the event loop
- **style** — pattern preference (early return, naming, function length)
- **nit** — taste; only include if memory tells you the team cares

Skip everything else. Two findings is better than ten. The senior engineer's time is the bottleneck.

For each finding, capture:

- `path` — file path from the diff
- `line` — line number in the new version (right-side)
- `category` — one of the labels above
- `comment` — one or two sentences. Direct, no "you might want to consider…"
- `suggestion` — optional `suggestion` block (GitHub-flavored markdown ```` ```suggestion ```` ) if you can write the exact fix

## Step 4 — Post the review

If `GITHUB_TOKEN` is set:

`jettson_http_request` POST `https://api.github.com/repos/${owner}/${repo}/pulls/${pull_number}/reviews`

Body:
```json
{
  "event": "COMMENT",
  "body": "First-pass review by Jettson. The senior reviewer will follow up.",
  "comments": [
    { "path": "...", "line": 12, "body": "<comment>" },
    …
  ]
}
```

If `GITHUB_TOKEN` is unset, skip the post and include the comments inline in your final result instead.

## Step 5 — Memory: learn from this review

For each `category` that appeared in your findings AND wasn't already in memory:

`jettson_memory_put`:
- namespace: `coding_standards`
- key: `pattern_${category}_${one-word-distinguisher}` (e.g. `pattern_style_early_return`)
- value: a one-sentence rule the team would actually post in their style guide
- importance: 6 for style/nit, 8 for bug/security, 7 for perf
- tags: ["review", category]

If a memory already exists for the same pattern, do NOT write a duplicate — `jettson_memory_put` would version it without adding value. Skip silently.

## Step 6 — Final result

Return:

```json
{
  "pr_url": "${PR_URL}",
  "comments_left": <int>,
  "categories": { "bug": 0, "security": 0, "perf": 0, "style": 0, "nit": 0 },
  "memory_writes": <int>,
  "posted_to_github": <true|false>,
  "review_body": "<the same body you posted, for the local-only case>"
}
```

Be terse. The team is reading you on every PR.

SAMPLE OUTPUT

What you get back.

Representative output. Real runs vary with your memory state and the live data the agent finds — the shape stays consistent.

expected-output.md
# Sample output

Representative review on a fake PR adding a `/users/:id/avatar` endpoint. Your real output depends on the PR and the memories you've accumulated.

## What the agent posted on the PR

```
First-pass review by Jettson. The senior reviewer will follow up.
```

### Inline comments (4 left, of ~12 considered)

**`apps/api/src/routes/avatars.ts:42`** — *bug*

> The `id` param comes straight off `req.params` and lands in a SQL string at line 49 — that's a parameterized-query bypass. Use the prepared-statement helper used everywhere else in this file.
>
> ```suggestion
> const avatar = await db.avatars.findOne({ where: { user_id: id } });
> ```

**`apps/api/src/routes/avatars.ts:67`** — *security*

> No size check before writing to disk. A 2 GB upload here will fill the volume. Add the `maxBytes` guard used in `routes/uploads.ts` (memory says we cap user uploads at 5 MB).

**`apps/api/src/routes/avatars.ts:18`** — *style*

> Nested if-else inside the route handler — the rest of `routes/` uses early returns for this exact shape. Pull the validation up so the happy path is unindented.

**`apps/api/src/routes/avatars.ts:33`** — *perf*

> `Promise.all` over a `.forEach` with an `await` inside — the current code is sequential by accident.

## Final result

```json
{
  "pr_url": "https://github.com/your-org/your-repo/pull/123",
  "comments_left": 4,
  "categories": { "bug": 1, "security": 1, "perf": 1, "style": 1, "nit": 0 },
  "memory_writes": 2,
  "posted_to_github": true,
  "review_body": "First-pass review by Jettson. The senior reviewer will follow up."
}
```

## Memories the agent wrote

After this run the `coding_standards` namespace gains two entries (the other two patterns were already in memory from earlier reviews):

```
namespace=coding_standards  key=pattern_security_input_validation  importance=8
  → "Validate route params at function entry before they reach SQL or the filesystem. Use the prepared-statement helper, not template strings."

namespace=coding_standards  key=pattern_perf_sequential_await  importance=7
  → "forEach + await is sequential — the team always wants Promise.all here. Flag whenever a loop awaits inside .forEach/.map without Promise.all."
```

## What this looks like by the 10th run

After ~10 PRs the `coding_standards` namespace usually settles around 12–18 memories. From there the agent's review pass shifts: it stops re-flagging the patterns it has already memorized as house standards (no more "use early returns" comments — the team's seen that one) and only surfaces *new* shapes. Reviews shrink from ~4 comments to ~1-2 — exactly what the senior reviewer wanted in the first place.

CUSTOMIZE

How to make it yours.

  • Seed your team's style upfront

    POST /api/v1/memory with your house rules before the first run so the agent doesn't have to re-discover them.

  • Stricter passes

    Change the Review pass section in agent.md from 'senior peer review' to 'security-focused' or 'performance-focused'.

  • Gate merges

    Flip the review event from COMMENT to REQUEST_CHANGES in step 4 of agent.md.

  • Different VCS

    Swap the GitHub endpoint for GitLab or Bitbucket. The prompt logic is identical.

Ship your own version in 30 minutes.

Sign up, fork the example, and an agent of your own goes to work. Your CEO will think you spent the week on it.