watchloop
Health Gecti
- License รขโฌโ License: MIT
- Description รขโฌโ Repository has a description
- Active repo รขโฌโ Last push 0 days ago
- Community trust รขโฌโ 12 GitHub stars
Code Basarisiz
- rm -rf รขโฌโ Recursive force deletion command in lo-log.sh
Permissions Gecti
- Permissions รขโฌโ No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
๐ผ Claude Code skill: an unattended nightly loop that turns Linear tickets into reviewed PRs
๐ผ watchloop
Tickets in. Reviewed pull requests out. Nobody watching.
A Claude Code skill that runs your Linear board
overnight and hands you a morning of pull requests to read.

What makes it different
The whole interface is two surfaces. A ticket in Linear, and a comment on a
pull request. There is no chat window to steer, no label to remember, no plan to
approve inside the tracker. To change the direction of the work you comment on the
PR, and the loop reads it, answers it by name, and acts on it. That works on a
merged PR too, which is where it earns its keep: merge, note the follow-up work
the PR spotted but left out of scope, and the loop turns your note into the next
ticket by itself. Teammates can steer it the same way, on purpose.
Draft means something. A PR leaves draft only on evidence โ a review, a fix
pass over that review, a screenshot when a user can see the change, no merge
conflict, and CI green on the head commit. It never leaves draft on an agent's
say-so. So what is not a draft in the morning is what is actually ready, and the
drafts are the pile you can ignore until you have time.
Idle costs nothing. Nothing runs until there is work. The gate probes
capacity, your open PRs and the Linear ready column every 60 seconds in pure
shell โ no model call, no turn started. A night with an empty board costs
nothing at all, not "not much".
It runs on your machine, on the Claude you already pay for. No hosted sandbox,
no per-session credit, no repo access granted to a third party. That also means it
uses whatever the machine has: it measures free memory every probe and runs as many
agents as will really fit โ one per LO_RAM_PER_AGENT gigabytes โ so parallelism
is bounded by your laptop rather than by a plan.
A person decides every merge. Author and reviewer are the same model, so "no
blockers left" is evidence about care, not proof of correctness. The loop stops at
a reviewed, non-draft PR. It merges only when a person on the merge list
(LO_SLACK_MERGE_EMAILS) names that PR in Slack. The one standing order is the fix
of a small break of the base branch build: a type, lint or test failure with one
cause and no change a user sees. The loop never merges into the default branch.
What it does, in order
- The gate blocks until there is work โ capacity, your PRs, the Linear ready
column. - An agent takes the ticket, moves it to In Progress, branches, opens the
draft PR before it writes any code, writes the code, tests it in a real browser,
and stops. - A second agent reviews that PR in a fresh context โ it has the diff, the
ticket and your repo's agent guide, and none of the reasoning the author talked
itself into. It logs the review as one entry in the PR's single log comment, makes exactly
one fix pass over what it found, and corrects the PR body where the diff moved past it. - The PR leaves draft on the five gates, or stays a draft.
- Your comment re-opens any of it. An unanswered comment on one of its PRs
outranks every other kind of work on the next tick.
Every agent gets its own repo clone, Terminal window and real Chrome, which is
why front-end tickets work here: the screenshots on the PR come from driving the
actual screen, not from a headless guess.
The mechanics โ the shell gate, and how the loop tells your comments from its own โ
are in HOW-IT-WORKS.md.
Who this is for
People who already run coding agents locally and would rather spend a machine than
a per-seat credit. The install is honestly longer than "connect GitHub", and the
constraints are real:
- macOS or Linux, and Claude only. It drives Claude (Opus) agents through
multiclaudeand reads Linear
throughagent-codemode, which
reads Claude Code's OAuth from the macOS Keychain, or from~/.claude/.credentials.jsonon Linux. - A Linux server has no real Chrome. Its agents run in
screensessions
without Claude in Chrome, so they test front-end work with headless Playwright. - One machine. Parallelism caps at what one laptop's memory holds.
--dangerously-skip-permissionsis required. The agents run unattended with
permission prompts off. That is the point, and it is also the risk โ give the
loop a repo where the worst an agent can do is open a bad PR.- Your repo needs its own agent guide (
CLAUDE.md). The prompt handed to each
agent is short because the guide supplies branching, local checks, the PR
template, testing and security.
Install and run
You also need gh (authenticated), jq, and the
Linear MCP server connected to the session that runs
the loop.
git clone https://github.com/janwilmake/watchloop.git \
~/.claude/skills/watchloop
cd ~/.claude/skills/watchloop
cp .env.example .env && $EDITOR .env
Installed it before 15 Oct 2026, as linear-orchestrator? Move both
folders, point the remote at the new name, and start it with /watchloop:
mv ~/.claude/skills/linear-orchestrator ~/.claude/skills/watchloop
mv ~/.claude/linear-orchestrator ~/.claude/watchloop
git -C ~/.claude/skills/watchloop remote set-url origin https://github.com/janwilmake/watchloop.git
Then start it from your repo:
cd /path/to/your/repo
claude --dangerously-skip-permissions
/watchloop
status reports what is running; stop ends the loop and lists the PRs it
produced.
Run it on a Linux server
The loop also runs on a Linux server (tested on Ubuntu 24.04), which keeps it
running when the laptop sleeps. On the server:
- Install
git,gh,jq,screen, Node and Claude Code, and log in togh,
Claude Code and the Linear MCP (claude mcp login linear) as the account the
loop acts as.agent-codemodereads the Linear login from~/.claude/.credentials.json. - Mark the agent slot folders
~/.claude/agents/agent-Nas trusted in~/.claude.json, and accept the Bypass Permissions warning once. Otherwise
each new agent stops at a question nobody answers. - Optional, for front-end work: Chrome on a virtual display (Xvfb), with the
Claude extension signed in and x11vnc serving that display on localhost:5900.ccapasses--chromeonly when Chrome is installed; without it, agents test
with headless Playwright. - Start the loop in a
screensession, so it outlives your ssh connection:screen -dmS orchestrator bash -lc 'cd /path/to/repo && claude --dangerously-skip-permissions "/watchloop start"'.
To watch it from a Mac or a Linux desktop, set LO_REMOTE_HOST (and, for the
browser view, LO_REMOTE_VNC_PASSWORD_FILE) in .env and run./watch-remote.sh. It opens one terminal window per agent and the
orchestrator, adds windows for new agents, closes a window when its agent ends,
and opens a VNC view of the server's Chrome: Screen Sharing on a Mac; TigerVNC'svncviewer, else Remmina, on Linux. On Linux, LO_REMOTE_TERMINAL picks the
terminal (for example kitty or gnome-terminal --); without it the script
takes the first one it finds. Ctrl-C, or ./watch-remote.sh stop, closes every
view; the loop keeps running. Close a single window with the window manager,
never Ctrl-C: keys typed in a window reach that agent.
Configure with .env, not the skill file
All the values that change per user live in .env beside SKILL.md. It is
gitignored, so your paths and names never reach the repo โ which is what lets the
skill be a symlink to a checkout:
LO_REPO="/path/to/your/repo" # local checkout the agents clone from
LO_BASE="dev" # base branch
LO_TEAM="Your Team" # Linear team name
LO_PREFIX="ENG" # ticket id prefix
LO_TIER1="Preferred Assignee" # display name. ONLY these assignees are taken
LO_TIER2="Fallback Assignee" # display name
LO_ALLOW_UNASSIGNED="0" # 1 = also take unassigned tickets (default off)
LO_ALLOW_BACKLOG="0" # 1 = fall to Backlog when Todo is empty (default off)
LO_OWNER="" # this instance's tag; required if two share a repo
LO_RAM_PER_AGENT="2.5" # GB per agent (claude + vite + chrome)
LO_MAX_AGENTS="0" # ceiling on concurrent agents; 0 = unlimited
LO_FEEDBACK_SINCE="2026-08-18T17:00:00Z" # the day you installed this
LO_RAM_PER_AGENT is the one people get wrong: it is a divisor, not a threshold.
Every tick spawns free memory / LO_RAM_PER_AGENT agents โ all of them, not one,
so the loop reaches full capacity on its first tick with work. LO_MAX_AGENTS
defaults to 0, meaning memory is the only ceiling; set a positive number to
hold part of the machine back. The default divisor assumes one Claude session,
one dev server and one Chrome โ a stack with Docker or a local database costs far
more, and the probe cannot detect that.
What it takes is narrow on purpose. Only tickets in Todo assigned toLO_TIER1 or LO_TIER2. Unassigned tickets and the Backlog column are each
one switch away (LO_ALLOW_UNASSIGNED, LO_ALLOW_BACKLOG) and both default to
off โ a name on a ticket in a ready column is somebody deciding it is ready, and
that decision is the signal the loop runs on.
Running two orchestrators against one repo โ say one per laptop โ needsLO_OWNER set to a different tag in each. Splitting by assignee separates them
on the tracker, but not on GitHub: every instance writes the same ๐ marker,
and that marker is what decides which PRs a loop reviews, promotes and answers
comments on. With LO_OWNER the marker becomes ๐ lo:<owner> and the two stop
overlapping. Both instances must run this version for the split to hold โ an
older one matches the bare marker and still adopts everything.
Both gate.sh and the tick read these, so there is nothing to edit insideSKILL.md.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi