Documentation
Noctra is an autonomous ticket-to-PR agent. Point it at a trigger source — Linear, Jira, or GitHub Issues — and it implements tickets, opens pull requests, and sees them through — answering reviews and fixing CI — while you sleep.
Introduction
Noctra is an autonomous Linear → PR agent: it picks up tickets from your Linear workspace and turns each one into a pull request, with Jira and GitHub Issues supported as alternative trigger sources.
Noctra runs as an installable Go CLI. On a timer it polls your configured trigger source — Linear, Jira, or GitHub Issues — for issues, dispatches Claude Code, OpenAI Codex, GitHub Copilot, or Antigravity CLI to implement each one in an isolated git worktree, optionally runs a second-model review, opens a PR with the GitHub CLI, and marks the ticket as handled (moving it to your review state on Linear or Jira, or removing the trigger label and commenting on a GitHub issue). The PR body and commit footer name the backend and the model that did the work — e.g. Claude Code (Opus 5.5) or OpenAI Codex (GPT-5.5); Copilot and Antigravity show the backend name only. With auto-iterate enabled it then watches those PRs and pushes follow-up commits in response to review feedback and failing CI.
- Self-hosted & open source — runs on your machine or a Raspberry Pi.
- Uses your own agent CLI: Noctra runs whichever coding agent you've logged into on your machine, with your subscription or an API key, and never stores agent credentials. Subscription usage counts against your plan's limits and terms.
- Multi-repo — one instance serves many repos, routed per ticket.
Quick start
You'll need the GitHub CLI (gh, authenticated) and at least one supported agent CLI: Claude Code, OpenAI Codex, GitHub Copilot, or Antigravity CLI. Install Noctra itself with the script, Homebrew on macOS (brew install onelastcommit/tap/noctra), go install, or a prebuilt binary from GitHub Releases.
# One-liner: install the latest release binary (no Go toolchain) curl -fsSL https://raw.githubusercontent.com/onelastcommit/noctra/main/scripts/install.sh | sh # macOS (Homebrew): brew install onelastcommit/tap/noctra # or: go install github.com/onelastcommit/noctra/cmd/noctra@latest claude # or: codex login / agy — authenticate your agent once gh auth login # GitHub access for PRs noctra github login # optional: act on GitHub as noctra-agent[bot] noctra setup # guided ~/.noctra/ config (backend, Linear, notifications) noctra doctor # preflight tokens, tools, repos, models noctra # start the poll loop
noctra: command not found? The install script drops the binary in ~/.local/bin — if that's not on your PATH, add it (the installer prints the exact line for your shell) or open a new shell. Then map each Linear project to a repo with a Repo: directive (see multi-repo routing), move a ticket into your trigger state or add the trigger label, and watch it become a PR.
Agent backends
Noctra implements each ticket with the coding agent you choose via AGENT_BACKEND — Claude Code (claude, the default), OpenAI Codex (codex), GitHub Copilot (copilot), or Antigravity CLI (agy). You only need the CLI for the backend you select; noctra doctor checks for the right one and shows whether it is using a subscription login, an API key, or a cloud provider. Authenticate it once on the host. Noctra runs whichever login the CLI already has and never stores agent credentials. Each vendor's own terms and limits apply:
- Claude Code: log in with
claude, or setANTHROPIC_API_KEY, which takes precedence over a subscription login and is billed per token. Noctra runs Claude headlessly (claude -p), which counts against your plan's usage limits. Anthropic announced a separate monthly Agent SDK credit for this kind of usage and then paused it, so check Use the Claude Agent SDK with your Claude plan and Use Claude Code with your Pro or Max plan for the current position. - OpenAI Codex:
codex loginwith ChatGPT, which uses your ChatGPT plan's limits, or an API key (OPENAI_API_KEY), billed per token. See Using Codex with your ChatGPT plan and Codex authentication. - GitHub Copilot: the standalone
copilotCLI (npm i -g @github/copilot, Node 22+) needs a Copilot plan and signs in throughgh auth loginor a token inCOPILOT_GITHUB_TOKEN/GH_TOKEN. Each prompt uses premium requests from your plan; see Requests in GitHub Copilot and the GitHub Terms of Service. - Antigravity CLI: install
agyfrom antigravity.google and run it once to sign in with your Google account, or configure a Gemini API key. Usage counts against your Google AI plan's quota; see Plans and AI credits.
Team use: if several people's tickets run through one instance, prefer an API key or a team or organisation plan over one person's individual subscription.
Agent plugins
Give the agent curated skills on every run, whichever backend you use. noctra setup asks what you mostly build, then which optional packs to add, and writes them to AGENT_PLUGIN_PACKS:
engineering(always on with any pack) — superpowers' TDD, systematic debugging, verification-before-completion and receiving-code-review; agent-skills' code simplification; ponytail.frontend— impeccable, taste-skill, GSAP (core, timeline, ScrollTrigger, React, performance), Vercel's React best practices, Anthropic's webapp-testing.backend— agent-skills' API and interface design; Matt Pocock's codebase design.security(optional) — Trail of Bits' differential review and sharp edges.content(optional) — Corey Haines' copywriting; humanizer.
Every plugin is pinned to an exact upstream commit, and only its listed skills load — no hooks, commands, MCP servers, symlinks, or downloaded binaries, and no skills that wait for a human. Claude Code gets them via --plugin-dir; Codex, Copilot, and Antigravity get them copied into the worktree's .agents/skills/ for the run, git-excluded so they can't end up in a PR, and removed afterwards. Setup downloads your packs into ~/.noctra/plugins (PLUGINS_DIR) as soon as you choose them and every start re-checks them, so editing .env by hand works too; a failed download never blocks a ticket. The startup banner and noctra doctor show what's active. Anything else goes in AGENT_PLUGINS_EXTRA as owner/repo@<commit SHA>, at your own risk — it's shown as unvetted.
Plugins are off by default, so existing installs are unchanged. webapp-testing lets the agent check a UI change in a real browser and needs Python Playwright with Chromium (pip install playwright && python3 -m playwright install --with-deps chromium); without it that one skill is left out with a warning and everything else still loads. Skills are fetched from their upstream repositories on your own machine — Noctra never redistributes them, and each keeps its upstream licence.
Configuration
The setup wizard writes a .env under ~/.noctra/ with your backend, Linear key, optional agent plugin packs, optional Gemini/notification settings, an optional sweep schedule for automatic cleanup, and optional dashboard settings — or copy .env.example and edit it by hand (see the environment reference). Repos are managed separately — add them from Telegram (/addrepo), the CLI (noctra repos), or a Repo: directive on the Linear project (see multi-repo routing).
ENGLISH_VARIANT sets the spelling the agent and the Gemini review gate use for code comments, docs, commit messages, PR text, and review replies: british (the default) or american. Spellings fixed by a language or API (CSS properties, library identifiers) are left alone, and the agent follows the codebase's existing naming. Existing installs switch to British spelling on upgrade unless they set ENGLISH_VARIANT=american. Noctra's own notification wording doesn't change.
The loop
Each tick: poll the configured trigger source (Linear, Jira, or GitHub Issues) → resolve the repo from the ticket or project → create a worktree → dispatch the selected agent backend → optional review gate → commit, push & open the PR → mark the ticket as handled and notify. Tickets run concurrently up to MAX_CONCURRENT, each in its own worktree. If the agent determines a ticket requires no changes, Noctra archives it instead of opening an empty PR.
Trigger modes
Noctra can poll Linear (default), Jira Cloud, GitHub Issues, or any combination. Set TICKET_SOURCES to a comma-separated list of sources to poll (e.g. linear,jira,github).
With Linear, pick up work from a state-based queue (usually the Next column) or from a label-based queue using the noctra label. State mode is useful when Linear workflow state is the source of truth; label mode lets you opt tickets in without moving them between states. After the PR is opened, Noctra moves the ticket to your IN_REVIEW_STATE.
With GitHub Issues, Noctra scans the repos listed in GITHUB_ISSUES_REPOS for open issues carrying the GITHUB_TRIGGER_LABEL label. It implements them the same way — same agent dispatch, same PR workflow, same notifications. After the PR is opened, Noctra removes the trigger label and comments on the issue with a link to the PR (GitHub Issues has no state-column concept, so there is no IN_REVIEW_STATE transition).
With Jira Cloud, Noctra polls the project in JIRA_PROJECT via JQL for issues in the JIRA_TRIGGER_STATUS status (or carrying the JIRA_TRIGGER_LABEL label), authenticating with JIRA_USER_EMAIL + JIRA_API_TOKEN against your JIRA_BASE_URL. Repo routing comes from Repo: / Branch: directives in the issue description, exactly like the others. After the PR opens, the issue transitions to JIRA_IN_REVIEW_STATUS.
Multi-repo routing
The target repo is chosen per ticket from its Linear project — not a single global path — so one instance serves many repos with no config edits to switch between them. Repos are cloned on demand into ~/.noctra-repos/ and lock-guarded against concurrent clones.
Adding repos
There are three ways to register a repo with Noctra:
Repo:directive — add aRepo:line to the Linear project's description and every ticket in that project routes to that repo.- Telegram — send
/addrepo owner/name(or a full git URL) from chat. - CLI — run
noctra repos add owner/nameto register a repo from the terminal.
All three accept owner/name (expanded to a GitHub HTTPS URL) or a full https:// / git@ git URL verbatim — so SSH, GitLab, and other non-GitHub hosts work too. An optional Branch: directive (in the project description) overrides the default branch (otherwise auto-detected from origin/HEAD). Use noctra repos to list registered repos.
# In the Linear project's description: Repo: your-org/your-repo Branch: main # optional — defaults to the repo's default branch
Resolution order at dispatch — the first match wins: (1) the project Repo: directive, (2) REPO_PATH from .env as a single-repo fallback if set. With neither, the ticket is skipped with a Linear comment. The host needs git access to each repo — an SSH key, or gh auth login / GH_TOKEN for HTTPS — and Noctra checks access with git ls-remote before cloning.
Worktrees & logs
Each ticket gets an isolated worktree at ~/.noctra-worktrees/<IDENTIFIER> on a noctra/<id> branch, so parallel tickets never share a working directory. Per-ticket logs live at .agent-logs/<IDENTIFIER>.log and append across attempts.
Agent Teams
Claude-only. Set USE_AGENT_TEAMS=true and a lead Claude agent delegates implementation, tests, and review to teammates running in parallel — stronger on complex tickets, at the cost of more tokens per run. Requires a recent claude CLI; it doesn't apply to the Codex or Copilot backends. Off by default, where each ticket runs as a single agent session — fast, cheap, and light enough for a Raspberry Pi.
Dashboard
Set DASHBOARD_ADDR (e.g., :8080) and DASHBOARD_TOKEN to enable a built-in web dashboard — a Preact-powered, night-shift observatory UI built around dark tones and live telemetry. It shows active runs, queued tickets with retry counts, skipped tickets, and budget/usage stats — streamed live over SSE so the page updates in real time without polling. Each active run exposes a log tail you can follow directly in the browser; logs redact secrets (API keys, tokens, and other sensitive values) automatically so they are safe to view on screen. If only a port is given, Noctra binds to 127.0.0.1 automatically; the server refuses to start without a token.
Authentication is two-tier: DASHBOARD_TOKEN grants viewer access (read-only monitoring), while DASHBOARD_ADMIN_TOKEN grants operator access — everything a viewer sees, plus controls to kill, requeue, pause, and retry runs directly from the UI. Authenticate with a Bearer header or a ?token= query parameter for browser access. noctra setup prompts for both values during first-time configuration.
The operator token also gates the control endpoints on the API — including POST /api/sweep, which queues an on-demand maintenance sweep and is what noctra sweep calls under the hood.
Auto-iterate: PR review feedback
Set AUTO_ITERATE_PRS=true and Noctra watches the PRs it opens. New conversation comments, reviews (changes-requested / non-empty comments), and inline review-thread comments trigger the selected agent backend to address them on the same branch and push a follow-up commit — inline comments are passed with their file:line so it knows exactly where each note applies. Comments that are commands directed at other bots (e.g., /dependabot rebase) are filtered out automatically. Each follow-up push includes per-finding replies on each review thread, explaining what changed and why.
Auto-iterate: CI failures
The same watcher reads each PR's check status. Once every check on the head commit has completed and at least one failed, Noctra fetches the failed-step logs and asks the selected agent backend to reproduce and fix them. CI is keyed by commit SHA, so it acts at most once per commit; review feedback and CI fixes share the MAX_PR_ITERATIONS budget and, when both are pending, are handled in one re-engagement.
Review gate
Provide GEMINI_API_KEY to enable an optional second-model review: before the PR opens, Gemini reviews the diff against the ticket. If it flags issues, the selected agent backend gets up to MAX_REVIEW_RETRIES fix passes. When the review passes, the gate posts inline, line-anchored comments on the PR — pinned to the exact lines it reviewed — so reviewers see what the second model checked. Leave the key empty to skip the gate entirely.
Learning loop
Noctra gets better at each repo over time. When a PR it opened is merged, it diffs the human edits layered on top of its last pushed commit — the corrections a reviewer applied before merging — and uses Gemini to distill them into concise, durable per-repo lessons & conventions kept in the state DB. On later runs against that same repo, those lessons are injected into the implementation and fix prompts, so the agent stops repeating the same mistakes. It's automatic and size-bounded — nothing to configure.
Maintenance sweeps
With SWEEP_ENABLED=true, a third loop runs alongside the ticket and PR watchers: on a schedule it sweeps repos and runs upkeep no one filed a ticket for, opening a labelled PR for each change. By default it targets every repo Noctra has cloned; set SWEEP_REPOS to a comma-separated list of owner/name slugs to limit sweeps to specific repos. Built-in tasks cover lint cleanup, dead code, dependency updates, test-coverage gaps, documentation drift, API modernization, and a conservative high-confidence bug scan. Run all of them or a subset via SWEEP_TASKS.
Schedule it with a cron expression in SWEEP_SCHEDULE (e.g. 0 0 * * * for nightly at midnight) or a fixed SWEEP_INTERVAL. SWEEP_MAX_TASKS caps how many run per cycle. A round-robin planner spreads tasks across repos — instead of exhausting all tasks on one repo before moving to the next, it interleaves them so every repo gets attention within the budget. A per-repo, per-task cooldown stops a task re-running too soon — so it stays cheap across many repos. A task can decline when there's nothing to do, so it never opens an empty PR. Adding your own task is one small file in internal/sweep.
Each sweep PR lands on a short noctra/sweep-<task> branch (e.g. noctra/sweep-deps-update), and its Repo: line shows the owner/name it targets. Sweep PRs still open on the older, repo-qualified branch names aren't matched, so a sweep may open a fresh PR beside one — close the old one.
Sweeps also run on demand, without waiting for the schedule — send /sweep from Telegram (nothing extra to configure) or run noctra sweep on the host. Both take optional filters: a task name, a repo, and a force flag that re-runs a task inside its cooldown. On Telegram the filters are bare words (/sweep lint-cleanup trade-mate); on the CLI they are flags (noctra sweep -t dead-code -r trade-mate -f). A manual sweep goes through the same worker pool and MAX_CONCURRENT accounting as a scheduled one, and it isn't recorded against the cooldown clock, so an ad-hoc run never shifts the scheduled cadence. Budget caps still apply — a paused or exceeded budget refuses a manual sweep. noctra sweep talks to the running daemon over the dashboard's admin API rather than sweeping itself, so it needs DASHBOARD_ADDR and DASHBOARD_ADMIN_TOKEN set.
A run that gets cut short doesn't lose its work. If a sweep runs out of time or hits its per-run token ceiling, Noctra commits whatever the agent has already changed, pushes the branch, and opens a draft PR with (partial) appended to the title. The body says up front that the diff is unverified — the run ended before the agent reached its own build-and-test step, so nothing on the branch is known to be green; review or close it before merging. The draft carries the same maintenance label as any other sweep PR, so auto-iterate claims it and a failing check drives a cheap, targeted fix pass instead of a fresh full-cost scan. The abort notification links the draft. If the run left nothing behind, no PR is opened.
Safety guards
MAX_PR_ITERATIONS— per-PR re-engagement cap; on reaching it Noctra stops and pings you.AGENT_TIMEOUT_MINUTES— hard timeout per agent run.MAX_DISPATCHES— daily (UTC) dispatch cap that pauses until midnight;MAX_RETRIES— per-ticket retry cap.- Rate-limit detection — backs off instead of burning quota.
TRUSTED_REVIEWERS— bots are ignored unless explicitly allow-listed.
Budget & cost
Optional daily caps keep an overnight run from running away. Set MAX_DAILY_TOKENS and/or MAX_DAILY_USD; when a cap is reached, Noctra pauses dispatching and auto-resumes at the next UTC midnight. Noctra captures real token and cost usage from every agent backend, so both caps track actual consumption. The caps are worth setting on a subscription login too: sweeps and Agent Teams can use a plan heavily, and that usage counts against your plan's limits. On a rate limit, RATE_LIMIT_STRATEGY=pause (the default) backs off for RATE_LIMIT_COOLDOWN seconds and resumes instead of burning quota or exiting.
Telegram
Noctra fans out notifications to every platform you configure — Telegram, Slack, Discord, or all three at once. Each notifier is independent; enable one or several.
Set TELEGRAM_ENABLED=true with a TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID for PR-ready pings, failure and rate-limit alerts, and a heads-up on every PR re-engagement. The same run loop also handles inbound Telegram commands through the command dispatcher — a two-way control channel for when you're away from your desk, with no separate process to start. Only your configured chat can issue commands. TELEGRAM_VERBOSE=true adds a notification on each ticket dispatch.
A daily credential check catches expired logins before they surface as failed runs. Once a day at noon (AUTH_CHECK_SCHEDULE, a cron expression in the host's local time, default 0 12 * * *; off disables) Noctra checks that GitHub, Linear, and the agent CLI are still logged in, without spending tokens. While a login is broken, each check sends one 🔑 message naming the service and the command that fixes it; the first check after it's fixed sends a ✅, and a healthy check sends nothing. Antigravity has no status command, so its login is only reported when a run fails. When an agent run does fail — in a ticket, plan, sweep, or PR follow-up — the alert now quotes the CLI's own output, and an auth error names the CLI and its login command (e.g. run claude auth login on the host). An auth-failed sweep doesn't start its cooldown, so it retries on the next cycle once you've logged back in.
| Command | What it does |
|---|---|
| /status | Active runs + session stats. |
| /tickets [project] [state] | Ticket counts by state, or list one state. |
| /ticket ENG-42 | Show a ticket's details. |
| /search-tickets <text> | Search Linear tickets by text (alias /find). |
| /requeue ENG-42 [context] | Re-queue a blocked/failed ticket, optionally with extra context. |
| /addrepo owner/name | Register a repo for ticket routing (accepts owner/name or a full git URL). |
| /kill ENG-42 | Stop a running ticket. |
| /sweep [task] [repo] | Run a maintenance sweep now; add --force to ignore cooldowns. |
| /help | List all commands. |
Slack
Set SLACK_WEBHOOK_URL to a Slack incoming-webhook URL and Noctra posts the same status messages it sends to Telegram — PR-ready pings, failures, rate-limit alerts, and PR re-engagements. A non-empty URL is the enable signal; there is no separate flag. Create the webhook under your Slack app's Incoming Webhooks settings and add it to the target workspace and channel.
Discord
Set DISCORD_WEBHOOK_URL to a Discord channel webhook URL. Noctra posts the same status messages as Telegram and Slack — a non-empty URL enables it. Create the webhook under Channel Settings → Integrations → Webhooks. Messages longer than 2,000 characters are truncated automatically, and all @-mention parsing is disabled so untrusted ticket content can never ping your server.
Trusted reviewers
Humans are always acted on. Bot reviewers are acted on only if their GitHub login is listed in TRUSTED_REVIEWERS (case-insensitive, comma-separated). The default is empty — humans only — so a confidently-wrong bot can't drive a bad change. Bot feedback is still logged.
Post as the Noctra app
By default Noctra comments and moves tickets as the user behind LINEAR_API_KEY. To act under its own identity instead, create a Linear OAuth app and set LINEAR_OAUTH_CLIENT_ID and LINEAR_OAUTH_CLIENT_SECRET. Noctra mints an actor=app token via the client-credentials grant and auto-renews it — no refresh token, no browser flow, nothing that expires on you. If the app credential ever fails to authenticate, it falls back to the personal API key and alerts you, so an expired token can't take the agent down.
GitHub as noctra-agent
By default Noctra opens PRs, pushes, and replies to reviews as whoever is logged into gh on the host. To give it its own identity, install the noctra-agent GitHub App on the repos Noctra should work on, then run noctra github login once. It links the host through a GitHub device flow and stores an instance key in ~/.noctra/github; your user token is never stored. From then on PRs, commits, labels, and replies come from noctra-agent[bot].
The app's private key never reaches your machine. The token service at https://auth.getnoctra.dev mints short-lived installation tokens, each scoped to a single repository. Coding agents only get read-only credentials, and Noctra does all pushing and PR work itself. In app mode, a token that can't be minted is an error; Noctra never quietly falls back to your personal gh login. The PR watcher also matches only the app's own PRs, so noctra/* branches you open yourself are left alone. The app has no Workflows permission, so pushes that touch .github/workflows/ are rejected.
GITHUB_AUTH_MODE=auto (the default) switches to the app once the host is linked. Set app to require it, or token to keep using personal credentials. noctra github status shows the active mode, and noctra doctor checks the link and that the token service is reachable. Keep gh logged in for the Copilot backend and noctra update.
What the token service stores
Only your GitHub user ID, the installation IDs you can access, and each linked host's public key, plus a random instance ID and the time it was linked. It never stores your GitHub user token, the tokens it mints, your login name, email address, repository names, or any code, and its short-lived replay and rate-limit counters are cleared within the hour. Uninstalling the app from an account drops that installation from every linked host; revoking the app under GitHub Settings → Applications → Authorized GitHub Apps, or running noctra github logout, deletes the host's record entirely. The service is open source at onelastcommit/noctra-auth, and you can self-host it with your own app by pointing NOCTRA_AUTH_URL at your deployment.
Moving from personal credentials
Nothing changes until you run noctra github login and restart. After that:
- New PRs come from
noctra-agent[bot], and the PR watcher only follows the app's PRs, so PRs Noctra opened under your account earlier are no longer iterated on. Finish or close them by hand. - If a repository limits who can push through branch protection, allow
noctra-agent. - In Docker, run
docker exec -it <container> noctra github loginonce; the key is kept on the/datavolume. - To go back, set
GITHUB_AUTH_MODE=tokenand restart, or runnoctra github logout.
Docker
A prebuilt image is published to GHCR with git, gh, and all the agent CLIs baked in — it runs anywhere Docker does, from your laptop to a $4 VPS. Provide keys via .env; repos are routed per ticket from each Linear project's Repo: directive. In a container, use HTTPS URLs / owner/name in the directive so GH_TOKEN authenticates the clone (SSH would need a mounted key).
# keys via .env; repos routed per-ticket from each Linear # project's "Repo: owner/name" directive (see Multi-repo routing) docker run -d --name noctra --env-file .env -v "$PWD/data:/data" \ ghcr.io/onelastcommit/noctra:latest docker logs -f noctra
Container auth uses API keys/tokens instead of interactive logins: LINEAR_API_KEY, AGENT_BACKEND, ANTHROPIC_API_KEY or OPENAI_API_KEY, and GH_TOKEN. Everything mutable — repo cache, worktrees, logs, PR cursor — lives under the mounted /data volume, so restarts keep their state. docker compose up -d works too.
Cloud
Always-on, no hardware. Templates for Fly.io, Render, Railway, and DigitalOcean each deploy the GHCR image with the same secrets as the Docker setup. Repos route per ticket via the project Repo: directive — nothing to mount or configure; use HTTPS URLs / owner/name so GH_TOKEN authenticates the clone.
All four persist /data (Fly volume / Render disk / Railway volume / droplet disk) so restarts keep state.
Running on a Raspberry Pi
Easiest: grab the prebuilt linux_arm64 (Pi 4 / 5, 64-bit OS) or linux_armv7 (Pi 3 / 32-bit OS) archive from Releases — no Go toolchain on the Pi needed. Prefer to cross-compile yourself? Noctra is a single static binary — build it and copy it over.
# Pi 4 / 5 (64-bit OS) GOOS=linux GOARCH=arm64 go build -o noctra ./cmd/noctra # Pi 3 / 32-bit OS GOOS=linux GOARCH=arm GOARM=7 go build -o noctra ./cmd/noctra
Then point your cron or service at the binary. No runtime dependencies.
Environment variables
| Variable | Purpose |
|---|---|
| LINEAR_API_KEY | Linear API key Noctra polls with. |
| LINEAR_TEAM_KEY | Team prefix (e.g. ENG) whose issues are watched. |
| AGENT_BACKEND | Coding agent that implements tickets: claude (default), codex, copilot, or agy. |
| TICKET_SOURCES | Comma-separated list of systems to poll for work: linear (default), github, jira. Example: linear,jira,github. |
| GITHUB_ISSUES_REPOS | Comma-separated owner/name repos to scan when github is an active ticket source (e.g. your-org/your-repo). |
| GITHUB_TRIGGER_LABEL | Label on GitHub Issues that marks an issue ready for Noctra to pick up. Falls back to TRIGGER_LABEL if unset. |
| JIRA_BASE_URL | Jira Cloud site URL when jira is an active ticket source (e.g. https://your-org.atlassian.net). |
| JIRA_USER_EMAIL | Jira account email, paired with JIRA_API_TOKEN for auth. |
| JIRA_API_TOKEN | Jira Cloud API token (create at id.atlassian.com → API tokens). |
| JIRA_PROJECT | Jira project key whose issues are polled via JQL (e.g. PROJ). |
| JIRA_TRIGGER_STATUS | Jira status that marks an issue ready to build (e.g. To Do). |
| JIRA_TRIGGER_LABEL | Jira label that triggers dispatch, as an alternative to status. |
| JIRA_IN_REVIEW_STATUS | Jira status set once the PR is opened (e.g. In Review). |
| TRIGGER_MODE | Pick up work by state (column) or label (Linear only). Default: state. |
| TRIGGER_STATE | State that marks a ticket ready to build (default: Next). |
| TRIGGER_LABEL | Label that marks a ticket ready to build when label mode is enabled. |
| IN_REVIEW_STATE | State set once the PR is opened (default: In Review). |
| REPO_PATH | Last-resort single-repo fallback when a project has no Repo: directive. |
| MAIN_BRANCH | Default base branch; overridden per-repo by a project Branch: directive. |
| AGENT_PLUGIN_PACKS | Curated skill packs loaded into every run on any backend: engineering, frontend, backend, security, content (CSV). Any pack enables engineering; empty or none = off (default). |
| AGENT_PLUGINS_EXTRA | Extra plugins at your own risk: owner/repo@<40-character commit SHA>, comma-separated. Every skills/<name>/SKILL.md in the repo is loaded. |
| PLUGINS_DIR | Where fetched plugins are kept (default: ~/.noctra/plugins). |
| ENGLISH_VARIANT | Spelling for agent and review-gate output (comments, docs, commits, PR text): british (default) or american. |
| MAX_CONCURRENT | How many tickets run in parallel. |
| POLL_INTERVAL | Seconds between Linear polls. |
| USE_AGENT_TEAMS | Claude-only: a lead agent delegates work to teammates in parallel. |
| MAX_DISPATCHES | Daily (UTC) cap on dispatches; when hit, dispatching pauses and auto-resumes at the next midnight (0 = unlimited). |
| MAX_RETRIES | Implementation retries before giving up on a ticket. |
| AGENT_TIMEOUT_MINUTES | Hard timeout for a single agent run. |
| GEMINI_API_KEY | Enables the optional second-model review gate. |
| GEMINI_MODE | How the review gate reaches Gemini: api (default, uses the key) or cli (local gemini CLI / Google login). |
| GEMINI_MODEL | Gemini model for the review gate. |
| MAX_REVIEW_RETRIES | Fix passes the agent gets after Gemini flags issues. |
| TELEGRAM_ENABLED | Turn Telegram notifications on/off. |
| TELEGRAM_BOT_TOKEN | Bot token for notifications. |
| TELEGRAM_CHAT_ID | Chat the bot posts to. |
| TELEGRAM_VERBOSE | Also notify on every ticket dispatch. |
| SLACK_WEBHOOK_URL | Slack incoming-webhook URL; non-empty enables Slack notifications (no separate flag). |
| DISCORD_WEBHOOK_URL | Discord channel webhook URL; non-empty enables Discord notifications (no separate flag). |
| AUTH_CHECK_SCHEDULE | Cron (host local time) for the daily check that GitHub, Linear, and the agent CLI are still logged in (default: '0 12 * * *'); off disables. |
| AUTO_ITERATE_PRS | Watch opened PRs and re-engage on feedback + CI. |
| MAX_PR_ITERATIONS | Per-PR re-engagement cap (shared: review + CI). |
| PR_POLL_INTERVAL | Seconds between PR scans. |
| STATE_DB | Path to the SQLite store for PR cursors, sweep cooldowns, and OAuth state (default: ~/.noctra/state.db). |
| STATE_FILE | Legacy JSON state file, migrated into STATE_DB on first run (default: ~/.noctra-state.json). |
| DASHBOARD_ADDR | Listen address for the dashboard HTTP server (e.g., :8080). If only a port is given, Noctra binds to 127.0.0.1. Empty = dashboard disabled. |
| DASHBOARD_TOKEN | Bearer token for viewer-tier (read-only) dashboard access (header or ?token= query param). The server refuses to start without it. |
| DASHBOARD_ADMIN_TOKEN | Bearer token for operator-tier dashboard access; grants viewer access plus controls (kill, requeue, pause, retry). |
| TRUSTED_REVIEWERS | CSV of bot logins to act on; empty = humans only. |
| SWEEP_ENABLED | Turn on autonomous maintenance sweeps (off by default). |
| SWEEP_REPOS | CSV of 'owner/name' slugs to sweep; empty = all cloned repos. |
| SWEEP_TASKS | CSV of sweep tasks to run; empty = all (lint-cleanup, dead-code, deps-update, test-coverage, doc-drift, modernize, bug-scan). |
| SWEEP_SCHEDULE | Cron expression for when to sweep (e.g. '0 0 * * *' for daily at midnight). Empty = use SWEEP_INTERVAL. |
| SWEEP_INTERVAL | Seconds between sweeps when no cron is set (default: 86400 = 24h). |
| SWEEP_MAX_TASKS | Cap on sweep tasks dispatched per cycle (default: 5). |
| MAX_DAILY_TOKENS | Daily token cap across agent runs; on hit, dispatching pauses and auto-resumes. 0 = unlimited. |
| MAX_DAILY_USD | Daily cost cap in USD based on real usage reported by the agent backend; 0 = unlimited. |
| RATE_LIMIT_STRATEGY | On a rate limit: pause (default, back off then resume) or shutdown. |
| RATE_LIMIT_COOLDOWN | Seconds to pause after a rate limit when strategy is pause (default: 1800). |
| LINEAR_OAUTH_CLIENT_ID | OAuth app client id to post as the Noctra app (actor=app); paired with the secret below. |
| LINEAR_OAUTH_CLIENT_SECRET | OAuth app client secret; Noctra mints + auto-renews a 30-day app token from these two. |
| ANTHROPIC_API_KEY | Claude auth when running headless (Docker/cloud), instead of an interactive login. |
| OPENAI_API_KEY | Codex auth when running headless, instead of codex login. |
| GITHUB_AUTH_MODE | How Noctra acts on GitHub: auto (default, uses the noctra-agent app once noctra github login has linked the host), app (fail if not linked), or token (personal credentials). |
| NOCTRA_AUTH_URL | Token service that noctra github login links to and that mints app tokens (default: https://auth.getnoctra.dev). Self-hosters point it at their own deployment. |
| GITHUB_AUTH_DIR | Where the linked instance ID and private key live (default: ~/.noctra/github). |
| GH_TOKEN | PAT for gh PR creation + git push in containers (repo + PR scope); also authenticates the Copilot backend. |
| GIT_USER_NAME | Commit author name (defaults to a Noctra bot). |
| GIT_USER_EMAIL | Commit author email (defaults to a Noctra bot). |
CLI commands
noctra— start the poll loop (default).noctra setup— interactive configuration wizard for~/.noctra/(includes backend, agent plugin packs, Linear, Telegram/Slack/Discord, sweep schedule, and dashboard).noctra repos— list, add, or remove registered repos (noctra repos add owner/name,noctra repos remove owner/name).noctra doctor— preflight tokens, local tools, repo routing, and model access, and show which agent auth is in use (add--jsonfor machine-readable output).noctra update— self-update a release binary: download the latest, verify its checksum, and swap in place (--restartrestarts the service after).noctra install-service— write asystemd --userunit pointing at the installed binary (--startto enable, start, and keep it running after logout).noctra uninstall— remove the service and installed binary; add--purgeto also delete~/.noctra*state (config, cloned repos, worktrees, PR cursor), and--forceto skip the confirmation.noctra start/stop/restart/status— control thesystemd --userservice from the binary.noctra logs— tail the service logs (-fto follow).noctra sweep— run a maintenance sweep now instead of waiting for the schedule (--task,--repo,--force); needs the running daemon's dashboard admin API.noctra github login/logout/status— link this host to the noctra-agent GitHub App via device flow (--forcereplaces an existing link), unlink it and delete its key (--forcedeletes the local key even if the token service can't be reached), or show the active GitHub auth mode (--repo owner/namealso tests a read token for that repository).noctra cleanup— prune stale branches, worktrees, and old logs (add--forceto remove everything stale non-interactively).noctra completion bash|zsh— print a shell completion script.noctra version— print the build version.