This repository has no description
1

Configure Feed

Select the types of activity you want to include in your feed.

1 1 0

Clone this repository

https://tangled.org/filipstal.tngl.sh/loup https://tangled.org/did:plc:bezepxnv2z7lnlxqjnhasyjd
git@tangled.org:filipstal.tngl.sh/loup git@tangled.org:did:plc:bezepxnv2z7lnlxqjnhasyjd

For self-hosted knots, clone URLs may differ based on your setup.



README.md

🔎 loup#

Turn user session recordings into cited pull requests & issues — on Tangled, over the AT Protocol.

loup is a webhook harness you drop into your repo. Point your session-recording provider at it; when a recording comes in, loup finds where the user struggled, locates it in your code, and opens a PR (with a fix) or an issue (for the fuzzy stuff) on Tangled — each citing the exact moment of confusion as a screenshot that deep-links into the recording.

Every artifact it creates — the PR, the issue, the screenshot citations — is a real AT Protocol record. No bespoke backend; the protocol carries the state.

 recording (mp4/mov) + session context
        │
        ▼  ffmpeg cuts citation frames at the hotspots
   findings ──► localize in your repo ──► PR (fix)  | gzipped patch in a round
        │                              └► issue     | flag for humans
        ▼
   open on Tangled with inline, video-deep-linked screenshot citations

Install#

npm install -g loup-cli    # installs the `loup` command

Setup#

Run loup init inside the repo you want loup to operate on. It scaffolds two files (and adds the secret one to .gitignore):

loup.config.json — non-secret, safe to commit:

{
  "service": "https://tngl.sh",
  "targetRepo": "your-handle.tngl.sh/your-repo",  // repo to open PRs/issues on
  "targetRepoDid": "did:plc:…",                   // that repo's DID
  "targetBranch": "main",
  "port": 4319
}

.env — secrets, never committed:

TANGLED_HANDLE=your-handle.tngl.sh
TANGLED_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx     # tngl.sh → Settings → App passwords
# ANTHROPIC_API_KEY=sk-ant-...              # optional — turns on the vision pass

No SSH key needed. loup posts over the AT Protocol (it writes pull/issue records to your PDS), not via git push. The only credential it needs is a Tangled app password — generate one at tngl.sh → Settings → App passwords and paste it into .env. Use an app password, not your account password.

Use#

loup serve                 # the real pipeline — analyzes & posts to Tangled
loup serve --demo          # offline replay of known-good PRs (no LLM, no network)

# from another terminal, send a recording (a link is optional, for deep-link citations):
loup send recording.mov --url https://youtu.be/VIDEO

loup serve posts for real as soon as .env has your Tangled credentials — it prints the live PR/issue URLs. If those credentials are missing it runs a safe dry-run (analyzes + drafts, posts nothing) instead of erroring.

loup serve --demo replays a fixed set of real, already-open PRs/issue offline — handy for a guaranteed demo with no network or API key.

The webhook also accepts a raw POST (multipart/form-data: video, optional video_url, optional text) — exactly the shape a recording provider would send.

How it works#

When a recording arrives:

  1. ffmpeg cuts it into one screenshot per second, each with its timestamp burned in.
  2. loup hands those frames + your app's source code (sourcePaths) to a Claude model (claude-opus-4-8 by default) under a single system prompt.
  3. The model watches the session frame by frame, finds every place the user hit a bug or got confused, cross-references the source for the root cause, and — for things it can fix — returns the corrected file.
  4. loup turns that corrected file into a patch with git diff (so it always applies), then opens a PR with it, or files an issue for the fuzzy stuff — each citing the exact frame, deep-linked back into the recording.

Pass optional --text notes alongside the recording (a provider's session events, your own annotations) to nudge the model — but it works from the recording alone.

Why Tangled / AT Protocol#

A pull request is a sh.tangled.repo.pull record (patch as a gzipped blob in a round); an issue is sh.tangled.repo.issue; a citation is a sh.tangled.feed.comment whose markdown body embeds the screenshot blob. loup just writes records to its own PDS — no clone, no push, no server to run for state. Because contribution is federated, it can open PRs/issues on any repo, not just its own.

Config#

File What
loup.config.json target repo (targetRepo, targetRepoDid, targetBranch), repoRoot (defaults to CWD), sourcePaths (files/dirs to feed the model), port, model
.env TANGLED_HANDLE, TANGLED_APP_PASSWORD, ANTHROPIC_API_KEY (the vision pass), optional LOUP_MODEL (never commit)

sourcePaths points loup at your UI source (templates, components, pages) so the model can locate issues and write fixes. loup serve posts for real once .env has TANGLED_HANDLE + TANGLED_APP_PASSWORD; without them it dry-runs.