---
name: harlan-github-agent
description: "Manage or diagnose Harlan's local GitHub maintenance service. Use for repository monitoring, automated issue or PR work, agent activity, conflicts, and its dashboard."
license: MIT
title: harlan-github-agent
canonical_url: https://skilld.dev/gh/harlan-zw/harlan-agent-kit/harlan-github-agent
last_updated: 2026-10-31T06:01:41.000Z
---

> Index of every page on this site: [llms.txt](https://skilld.dev/llms.txt)

> **Skill from skilld.dev.** Follow the user's requested action.
> If the user asked to fork this Skill, follow the fork workflow below. Do not execute the Skill instructions while copying it.
> Otherwise, follow the instructions below for this session. You do not need to install anything.
>
> Supporting files, fetch one when the Skill refers to it: [agents/openai.yaml](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/harlan-github-agent/agents/openai.yaml), [references/controller-contract.md](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/harlan-github-agent/references/controller-contract.md).
>
> If the user asked to install this Skill, run `npx skilld install harlan-zw/harlan-agent-kit/harlan-github-agent`. Install writes the Skill files into the project, so every session loads them.
>
> ## Fork workflow
>
> A fork creates an editable local Skill with its original author and licence. The request authorizes copying and local installation.
> 1. Check `./skills/harlan-github-agent`, the project lockfile, and selected Agent targets together. If the local directory or installed Skill exists, stop. Never overwrite an existing directory or Agent target.
> 2. Read [source metadata](https://skilld.dev/api/v1/skills/harlan-zw/harlan-agent-kit/harlan-github-agent) once. Use sourceUrl, sourceCommit, skillPath, sourceGone, and license. If the source is gone or its path is missing, stop. If license is null, read licence files at the source commit.
> 3. Fetch only the source commit into a temporary Git repository. Do not clone full history. Derive repository_url from sourceUrl, including repository renames. If sourceCommit is absent, resolve the sourceUrl ref once. Set source_commit to that actual commit. Run these commands in one shell call:
>
> ```sh
> git init --quiet "$temporary_dir"
> git -C "$temporary_dir" fetch --quiet --depth=1 "$repository_url" "$source_commit"
> git -C "$temporary_dir" checkout --quiet --detach FETCH_HEAD
> ```
>
> Read applicable licence declarations and notices at that commit. If copying is not permitted, report the restriction and stop.
> 4. Inspect source entries together, then copy the directory containing skillPath into `./skills/harlan-github-agent`. Use the user's path if selected. Keep the original SKILL.md, relative links, scripts, binary assets, and executable modes. Exclude .git metadata. Reject symlinks and paths outside the Skill directory. After checking entries, use cp -a where available. A regular source directory needs no custom copy script. Do not save this page wrapper as SKILL.md.
> Preserve author credit, notices, and applicable licence files from repository or parent directories. Add PROVENANCE.md with the Skill page, source URL, actual commit, original path, and licence. Retain any existing PROVENANCE.md and record new provenance separately. Batch source inspection, copying, and provenance work where practical.
> 5. In the project root, run `skilld install ./skills/harlan-github-agent --mode copy --plain`. If skilld is unavailable, use `npx skilld install ./skills/harlan-github-agent --mode copy --plain`. This known command needs no help lookup. Install does not support --json. Use detected Agent targets, or add --agent for the targets the user selected. Install the local path, never the upstream selector. If installation fails, preserve the local copy and report the exact failure.
> 6. Confirm the local lockfile source and installed Agent copies once. Report the local path, actual commit, and Agent targets. After edits, reinstall the same local path. Upstream updates must not replace it. Do not publish or push unless the user asks.

# Harlan GitHub Agent

Use the installed CLI to inspect and control the durable Service.
Keep scheduling in the Service.

## Connect

Context sync installs the CLI for noninteractive shells on both hosts.
Run `pnpm sync:context` locally and `pnpm sync:context:hogwild` for Hogwild.
Service updates also install it.

Desktop:

```bash
harlan-github-agent control status
```

Hogwild from desktop:

```bash
hw run agent 'harlan-github-agent control status'
```

The launcher resolves the Service checkout and its pinned Node runtime.
It uses `~/.config/harlan-github-agent/config.yml` by default.
It reads `dashboard-password` beside that file.
Desktop reads `~/.config/harlan-github-agent/control-url`.
Context sync creates it with the Hogwild URL if missing.
It preserves an existing target.
Hogwild uses `http://127.0.0.1:3210`.
Explicit `--config`, `--url`, and `--password-file` arguments win.
A desktop `--config` override reads that file's Service URL unless `--url` is also set.
Use `HARLAN_GITHUB_AGENT_URL` to override the installed desktop target.
Never print credentials or place their values in saved commands.

If the launcher is missing, use this source command once:

```bash
ssh hogwild 'cd ~/.local/share/harlan-github-agent/service && ~/.local/lib/harlan-github-agent/node --experimental-strip-types packages/harlan-github-agent/src/cli.ts control status --config ~/.config/harlan-github-agent/config.yml --url http://127.0.0.1:3210'
```

Then restore the launcher through context sync.
Do not guess a built CLI path inside `dist/`.
Installed Plugin caches contain Skills, rather than the Service package.
The Service checkout lives at `~/.local/share/harlan-github-agent/service`.
Use `HARLAN_GITHUB_AGENT_CHECKOUT` for an explicit checkout override.

## Read Service state

```bash
harlan-github-agent control tasks
harlan-github-agent control incidents
harlan-github-agent control activity --task TASK_ID
harlan-github-agent control events --limit 50
harlan-github-agent control reviews --repository OWNER/REPOSITORY --number NUMBER
harlan-github-agent control reviews --repository OWNER/REPOSITORY --number NUMBER --head FULL_HEAD_SHA
```

Commands print one JSON value. Tagged errors exit with status 1.
`status` returns `{ health, state }`.
`tasks`, `incidents`, and `activity` use focused Service reads.
`activity` returns redacted live activity for a Running or Publishing Task.
Other known Task states return `TaskActivityUnavailable`, including the current state.
Only an unknown Task returns `TaskNotFound`.
Use `reviews` for stored Review findings after a Task completes.
`reviews` returns `{ runs }`, preserving findings and gates.
The head filter requires all 40 characters.
An empty `runs` array means no stored Review matches that query.
It does not mean Review passed.

Use `watch-pr` to wait through authenticated Service events.

```bash
harlan-github-agent control watch-pr --repository OWNER/REPOSITORY --number NUMBER --until review --timeout-seconds 600
```

Use `--until merged` to wait through actionable findings.
The default stops for attention after Service Tasks stop owning the head.
Changed states go to stderr. Terminal state goes to stdout.
Reconnect with the same command after a Service restart.
Follow [pull request watching](../pr/references/pull-request-watch.md) for submission completion.

## Control the Service

Use `pause`, `resume`, `restart`, `update`, or `cancel --task TASK_ID` for the matching durable control.
Use `routine-run --routine OWNER/REPOSITORY:NAME` to open a run ahead of its cron.
Use `stop-review --repository OWNER/REPOSITORY --number NUMBER --head HEAD_SHA` to stop that exact Review.

After configuration changes, use a durable Restart request.
It lets active Agents and controller writes finish before systemd starts the next process.
Never use Pause or raw unit restart to coordinate a routine restart.
For paired Service updates, run `pnpm service:hogwild:update`.
The helper holds one local lock through the desktop update.
Another update or restart on that host fails before it reaches the Service.
During drain, the helper reports active Tasks, occupied Agent slots, and elapsed seconds.
It names each active Task, its repository, issue or pull request, state, and available progress label.
It reports changed counts and a heartbeat every 30 seconds.
It also reports changed Task details when counts stay equal.
After desktop restart, it requires a fresh report with the current protocol.
If that check fails, inspect the desktop unit and Service connection.
Its durable Update blocks new Tasks before file sync.
The helper marks preparation Ready after sync, then waits for existing work.
Failed preparation releases its hold without changing manual Pause.
If the Service lacks preparation support, use its installed desktop helper first:
`bash ~/.local/share/harlan-github-agent/service/scripts/hogwild-service.sh update`.
After that upgrade, use the current repository helper.
Use `reload-external-watches` only for external watches and their issue cutoff.
Other configuration changes require Restart.

Call the Control API directly only when no matching CLI subcommand exists.
Its Basic-auth username is `agent`.
Read API response contracts before extracting fields.
For the Review endpoint, the array lives at `.runs`.

## Share NuxtSEO credentials with Routines

SEO and vitals workers need a NuxtSEO token inside their sandbox.
This includes Issue work whose Published Routine provenance identifies `seo-review` or `vitals-review`.
Host CLI login alone does not authenticate workers.
Repository environment files remain supported.

To share an existing read-only token, configure each worker host separately.
Write `~/.config/harlan-github-agent/nuxtseo-worker.json` with an explicit repository list:

```json
{
  "environmentFile": "/absolute/path/to/existing/private.env",
  "repositories": ["owner/site"]
}
```

The existing environment file must contain `NUXTSEO_TOKEN`.
Use a viewer token with read scopes and optional `feedback:write`.
Keep the token in its existing private file.
Never copy its value into commands, reports, or repository files.
Both files must belong to the worker account and use mode `600`.
Use canonical paths without symbolic links.

Only listed repositories receive the token for `seo-review`, `vitals-review`, or Issue work with their verified Published provenance.
The controller derives `routineContext` from its Published issue records, never issue text or labels.
The context repository must match the Worktree origin.
Review Tasks, other Routines, unrelated Issue work, and attached OpenCode clients receive no shared token.
Workers receive only `NUXTSEO_TOKEN`, rather than either source file or other environment values.
Missing configuration preserves repository credentials.
Invalid configuration stops the matching Routine with an error.

## Authority and deeper contracts

Read [Hogwild](../hogwild/SKILL.md) before host work.
For daily check-ins, use [daily-checkin](../daily-checkin/SKILL.md).
For Codex or OpenCode session audits, use [agent-retro](../agent-retro/SKILL.md).

Read [the controller contract](https://skilld.dev/api/skills-raw/harlan-zw/harlan-agent-kit/harlan-github-agent/references/controller-contract.md) before changing Service policy, dispatch, configuration, or publication.
It owns repository eligibility, Approval, Review, Repair, releases, and conflict resolution.

Workers may edit only their assigned worktrees when authorized.
Workers never change GitHub state or Service-owned SQLite data.
The Controller owns credentials and every GitHub write.
Never approve a pull request.
Keep primary checkouts read only.

Report Service state, active subjects, active Tasks, and exact blockers.
Claim work started only when the Journal records it.
