Skip to content

Latest commit

 

History

54 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Localpager

Localpager is a local-first triage and paging tool for GitHub issues and pull requests.

It watches repo activity, queues new items, runs a classifier command, stores the structured result, and sends matching notifications to Discord.

This repository is an early extraction of a working triage prototype. The current code is intentionally small: it provides the worker, queue, GitHub and gitcrawl source adapters, classifier command boundary, SQLite state, Discord delivery, a bundled local model runner in localpager-agent/, offline prompt optimization tooling in prompt-optimizer/, and a small localpager operations CLI.

Current Commands

localpager                 validate config, show status, install services, test Discord
localpager reposhell       compatibility wrapper for the standalone reposhell CLI
localpager-enqueue-github  enqueue GitHub issues and PRs once
localpager-ingest-json     ingest one normalized item from JSON
localpager-watch           poll source adapters and enqueue items
localpager-worker          run classifier jobs and send notifications
reposhell                  standalone read-only repository shell service, exec, and shell

Classifier Contract

The worker runs a classifier command. By default it uses:

./scripts/localpager-classifier

That wrapper calls localpager-agent, which points Pi at a local OpenAI-compatible model endpoint and forces the final answer through the configured classifier schema.

The classifier command receives one target argument, usually a GitHub URL or owner/repo#number, and must print one JSON object to stdout:

{
  "topics_of_interest": ["bug", "build_release"],
  "description": "Why this item matters.",
  "caveats": []
}

Notification policy is deployment config, not classifier logic:

{
  "classifier": {
    "schema": "~/.config/localpager/classification.schema.json",
    "prompt_template": "~/.config/localpager/classifier.prompt.md",
    "topic_taxonomy": "~/.config/localpager/topics.json",
    "reposhell_default_repo": "localpager",
    "reposhell_visible_repos": ["localpager"],
    "context": {
      "github": {
        "include_body": true,
        "include_labels": true,
        "include_comments": true,
        "include_changed_files": true,
        "include_diff": true
      }
    }
  },
  "worker": {
    "agent_base_url": "http://127.0.0.1:1234/v1",
    "agent_context_window": 8192,
    "agent_max_tokens": 768,
    "agent_temperature": 0,
    "agent_top_p": 1,
    "agent_seed": 1234,
    "agent_presence_penalty": 0,
    "agent_frequency_penalty": 0,
    "agent_timeout_ms": 5000,
    "model_unavailable_retry_delay": "5m",
    "notify_topics_any": ["local_models", "open_weight_models"]
  }
}

When reposhell is enabled with a socket, run reposhell serve with matching reposhell config. localpager-agent owns tool exposure: it always provides final_json and adds a read-only bash tool whenever a reposhell socket is passed. The model sees a familiar bash-shaped tool, but Localpager enforces a read-only command allowlist against pinned repository snapshots. See Reposhell for standalone setup, config, direct commands, allowed command shapes, service mode, and troubleshooting.

If notify_topics_any is set, at least one classifier topic must match before a notification is created.

Classifier prompts, topic taxonomies, and schemas should be configured as a deployment profile. See Classifier Profiles. When classifier.topic_taxonomy is set, localpager-classifier generates a runtime schema that rejects topics outside that taxonomy. For the full worker → wrapper → renderer → agent chain, prompt placeholders, and schema-enum generation, see Classifier Pipeline and Profile Rendering.

For OpenClaw maintainer routing, this repo contains a self-contained v10 profile matching the evalstate benchmark label set:

examples/profiles/openclaw-routing.prompt.hbs
examples/profiles/openclaw-routing.schema.json
examples/profiles/openclaw-routing-topics.json

Those files are the default OpenClaw profile used by scripts/localpager-classifier when no profile flags or environment overrides are provided. The GEPA-reviewed candidate artifacts remain under prompt-optimizer/results/.

Before the classifier runs, Localpager renders GitHub context into the prompt: stored title/body/labels plus optional comments, changed files, and selected PR diff. Prompt templates can include that block with {{{github_context}}}. For prompt provenance and dataset artifact ownership, see Classifier Prompt Provenance. To test a prompt profile on a small live GitHub sample, use scripts/localpager-experiment.mjs; see Classifier Experiment Runner and Classifier Benchmark Metrics. Machine-specific runtime values, such as the loaded model context window, parallelism, context truncation budget, and loaded local model, belong in a deployment setup document. See Onur's Isengard Setup for the current OpenClaw/Gemma deployment. For Qwen NVFP4 through vLLM, see vLLM Qwen NVFP4 LocalPager Setup. For the Gemma 4 26B-A4B NVFP4 profile and local benchmark, see Gemma 4 26B-A4B NVFP4 on DGX Spark.

If the classifier writes lines like these to stderr, Localpager stores them with the result:

prompt: /path/to/prompt.md
session: /path/to/session-dir

Transient local model failures, such as the LM Studio endpoint being down, are requeued with model_unavailable_retry_delay and do not burn classifier attempts. To manually requeue matching dead jobs:

localpager requeue-jobs \
  --config ~/.config/localpager/config.json \
  --status dead \
  --last-error-contains "fetch failed"

Local Run

npm install --prefix localpager-agent
make test
make install
localpager validate --config examples/config.example.json
localpager-worker --config examples/config.example.json --once --dry-run-discord

Check the bundled agent:

npm --prefix localpager-agent run localpager-agent -- --status

To send Discord messages, pass a channel ID and set a bot token:

export DISCORD_BOT_TOKEN="<discord bot token>"
localpager-worker \
  --config examples/config.example.json \
  --discord-channel-id "$DISCORD_CHANNEL_ID" \
  --send-discord

Do not commit tokens, .env files, SQLite databases, classifier sessions, or prompt logs.

Localpager Agent

localpager-agent/ is the absorbed local model runner formerly used as an external command. It defaults to LM Studio's OpenAI-compatible endpoint:

http://127.0.0.1:1234/v1

The main environment variables are:

LOCALPAGER_AGENT_BASE_URL
LOCALPAGER_AGENT_MODEL
LOCALPAGER_AGENT_CONTEXT_WINDOW
LOCALPAGER_AGENT_MAX_TOKENS
LOCALPAGER_AGENT_TEMPERATURE
LOCALPAGER_AGENT_TOP_P
LOCALPAGER_AGENT_SEED
LOCALPAGER_AGENT_PRESENCE_PENALTY
LOCALPAGER_AGENT_FREQUENCY_PENALTY
LOCALPAGER_AGENT_TIMEOUT_MS
LOCALPAGER_AGENT_STATE_DIR
LOCALPAGER_AGENT_SESSION_DIR
LOCALPAGER_AGENT_PI_CMD
LOCALPAGER_AGENT_FINAL_SCHEMA

Sources

The default public source is the GitHub API:

export GITHUB_TOKEN="<github token>"
localpager-watch --config examples/config.example.json --source github --once

The gitcrawl source remains available for machines that already maintain a gitcrawl SQLite database:

localpager-watch --config examples/config.example.json --source gitcrawl --once

localpager-watch can run continuously under systemd. localpager-enqueue-github is the one-shot equivalent.

Services

Install compiled binaries and write user systemd units. The service installer writes localpager-worker.service, localpager-reposhell.service, localpager-watch.service, localpager-enqueue-github.service, and localpager-enqueue-github.timer.

make install
localpager install-service --config ~/.config/localpager/config.json --work-dir "$PWD"
systemctl --user daemon-reload
systemctl --user enable --now localpager-reposhell.service localpager-worker.service localpager-enqueue-github.timer

That setup runs the worker continuously and enqueues GitHub issues and pull requests on the timer. Enable localpager-watch.service instead if you want continuous source polling. If your classifier profile does not expose bash, you can leave localpager-reposhell.service disabled.

Check state:

localpager status --config ~/.config/localpager/config.json
localpager test-discord --config ~/.config/localpager/config.json
reposhell status --config ~/.config/localpager/config.json

Runtime State

The default SQLite state path is:

~/.local/state/localpager/localpager.sqlite

Localpager creates and updates SQLite tables from its GORM models at startup.

Override it with --db.

About

No description, website, or topics provided.

Resources

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages