diff --git a/docs/docs/architecture/agent-runtime.md b/docs/docs/architecture/agent-runtime.md index 41742b48e..8d54143c1 100644 --- a/docs/docs/architecture/agent-runtime.md +++ b/docs/docs/architecture/agent-runtime.md @@ -14,7 +14,9 @@ Every coding agent runs in a Docker container so ProPR can control runtime depen - Agent credentials mounted from a ProPR-managed per-agent directory or a configured existing host directory - GitHub credentials passed through `GH_TOKEN` and `GITHUB_TOKEN` - Agent, model, timeout, and task metadata passed as environment variables or CLI flags -- `--security-opt no-new-privileges`, `--cap-add CHOWN`, and Docker's default `bridge` network; the repository setup hook runs without sudo privileges before the agent entrypoint +- `--security-opt no-new-privileges`, `--cap-add CHOWN` (Vibe omits it), and Docker's default `bridge` network; the repository setup hook runs without sudo privileges before the agent entrypoint +- Memory, CPU, and process limits from `AGENT_CONTAINER_MEMORY_LIMIT` (default `6g`), `AGENT_CONTAINER_CPU_LIMIT` (default: available CPUs, capped at 4), and `AGENT_CONTAINER_PIDS_LIMIT` (default `512`) +- For every agent except Vibe, the host's `/tmp/git-processor` directory (all clones and worktrees) mounted at the same path so git works in the linked worktree - Structured stdout, stderr, exit code, duration, session ID, and token usage capture when the CLI exposes those fields All agents run from the unified Debian/glibc `propr/agent` image. Its internal base stage includes Node.js 22, Git and repository tooling, `scripts/init-firewall.sh`, a scoped `gh` wrapper, and entrypoint support used by the worker. The image uses Node.js 22 to satisfy current agent CLI engine requirements. Independent CLI build stages preserve Docker cache reuse when one configured version changes. @@ -44,12 +46,12 @@ Timeouts prevent runaway jobs and make failures visible in task state. Defaults | Agent | Timeout variable | Default | Loop variable | Default | | --- | --- | ---: | --- | ---: | | Claude Code | `CLAUDE_TIMEOUT_MS` | `86400000` (24 hours) | `CLAUDE_MAX_TURNS` | `1000` | -| Codex | `CODEX_TIMEOUT_MS` | `86400000` (24 hours) | `CODEX_MAX_TURNS` | `1000` | +| Codex | `CODEX_TIMEOUT_MS` | `86400000` (24 hours) | Not used | N/A | | Antigravity | `ANTIGRAVITY_TIMEOUT_MS` | `86400000` (24 hours) | Not used | N/A | | OpenCode | `OPENCODE_TIMEOUT_MS` | `86400000` (24 hours) | Not used | N/A | | Mistral Vibe | `VIBE_TIMEOUT_MS` | `86400000` (24 hours) | `VIBE_MAX_TURNS` | `1000` | -These task-execution defaults are shared across all coding agents and match the shipped `.env.example`. Planner keyword extraction and semantic relevance scoring default to 30 minutes per call and can be adjusted with `CONTEXT_ANALYSIS_TIMEOUT_MS`. +These task-execution defaults are shared across all coding agents and match the shipped `.env.example`. Planner keyword extraction and semantic relevance scoring default to 60 minutes per call and can be adjusted with `CONTEXT_ANALYSIS_TIMEOUT_MS`. When an implementation run reaches its execution timeout or maximum turn limit, ProPR preserves any workspace changes produced before the interruption. If changes exist, it commits and pushes them, opens the issue PR or updates the existing follow-up PR, and marks the result as potentially incomplete with the agent's last available summary and explicit remaining-work guidance. Other execution errors still fail normally, and an interrupted run with no changes has nothing to publish. @@ -60,8 +62,8 @@ When tuning these values, consider repository size, task complexity, provider ra The runtime should preserve these boundaries: - Keep git finalization outside the agent. -- Mount only the workspace and required credential directories. -- Avoid broad host filesystem mounts. +- Mount only the workspace, the shared git directory, and required credential directories. +- Avoid further host filesystem mounts. The shared git directory already exposes every cloned repository to the agent, so separate repositories with different trust levels onto separate stacks. - Keep credential directories scoped to the deployment user. - Monitor container CPU, memory, and duration. - Treat `--dangerously-*` CLI flags as acceptable only because Docker is the outer isolation boundary. @@ -131,7 +133,7 @@ The entrypoint checks for `/home/node/.claude/.credentials.json`, creates expect For implementation tasks, the worker invokes Claude Code with the prompt on stdin: ```bash -claude -p - [--model ] --max-turns N --output-format stream-json --verbose --dangerously-skip-permissions +claude -p - --no-session-persistence [--model ] --max-turns N --output-format stream-json --verbose --dangerously-skip-permissions ``` `--max-turns` comes from `CLAUDE_MAX_TURNS`. The worker captures Claude's stream JSON output, session ID, conversation log, and token usage when available. @@ -145,7 +147,6 @@ Common settings: ```bash HOST_CODEX_DIR=/home/your-user/.codex CODEX_TIMEOUT_MS=86400000 -CODEX_MAX_TURNS=1000 CODEX_STREAM_TRANSPORT=websocket CODEX_STREAM_IDLE_TIMEOUT_MS=1800000 CODEX_STREAM_MAX_RETRIES=5 @@ -154,7 +155,7 @@ CODEX_STREAM_MAX_RETRIES=5 The entrypoint checks for `/home/node/.codex/config.toml`, prepares `sessions` and `rules`, and avoids recursively changing bind-mounted workspace ownership. Codex runs as: ```bash -codex exec --json --dangerously-bypass-approvals-and-sandbox --config features.multi_agent=false --skip-git-repo-check --cd /home/node/workspace - +codex exec --ephemeral --json --dangerously-bypass-approvals-and-sandbox --config features.multi_agent=false --skip-git-repo-check --cd /home/node/workspace - ``` When a model is selected, ProPR adds `--model `. By default, ProPR selects a WebSocket-capable OpenAI provider with a 30-minute stream idle timeout so long, quiet turns are not pinned to a single HTTP response body. Set `CODEX_STREAM_TRANSPORT=sse` when WebSockets are unavailable or `CODEX_STREAM_TRANSPORT=inherit` to preserve a custom provider from the mounted Codex configuration. Codex emits NDJSON events that ProPR parses into logs, result text, session metadata, and token usage; reconnect notices remain visible without making a later successful turn fail. diff --git a/docs/docs/architecture/daemon.md b/docs/docs/architecture/daemon.md index 9525f4be3..346eecbb8 100644 --- a/docs/docs/architecture/daemon.md +++ b/docs/docs/architecture/daemon.md @@ -14,7 +14,7 @@ The daemon handles: - Monitoring configured repositories - Detecting eligible issues or events -- Resolving processing labels and model labels +- Resolving processing labels - Avoiding duplicate work - Creating queue jobs - Recording intake state @@ -29,7 +29,7 @@ It should stay lightweight. The daemon decides what should be processed; workers
↓
Find eligible issues or PR events
↓
-
Resolve labels, repository config, and models
+
Resolve trigger labels and repository config
↓
Skip work already processing or completed
↓
@@ -62,7 +62,6 @@ The daemon checks: - Open issues with primary processing labels - PR comments that should trigger follow-up work - State labels that show whether work is already running or complete -- Model labels that request a specific agent/model pair ## Label Detection @@ -82,7 +81,7 @@ AI-done AI-failed-* # e.g. AI-failed-post-processing, set when a phase fails ``` -Model labels route work to configured models. They are matched against `MODEL_LABEL_PATTERN` (default `^llm-(.+)$`): +Model labels route work to configured models; the worker's dispatch step resolves them. They are matched against `MODEL_LABEL_PATTERN` (default `^llm-(.+)$`): ```text llm-claude-opus5 @@ -91,31 +90,27 @@ llm-antigravity-pro-high llm-antigravity-opus46-thinking ``` -If an issue carries a trigger label but no model label, the daemon falls back to the deployment default model (`DEFAULT_MODEL_NAME`). The exact model labels available in a deployment come from AI Agents in the Web UI. +If an issue carries a trigger label but no model label, ProPR falls back to the deployment default model (`DEFAULT_CLAUDE_MODEL`, or the catalog default when unset). The exact model labels available in a deployment come from AI Agents in the Web UI. Reasoning level labels override the global `model_reasoning_level` setting for one issue. They match `level-low`, `level-medium`, `level-high`, `level-xhigh`, `level-max`, `level-ultra`, `level-ultracode`, or `level-auto`, case-insensitively. If multiple valid reasoning labels are present on the same item, ProPR chooses the highest-priority level in this order: `ultracode`, `ultra`, `max`, `xhigh`, `high`, `medium`, `low`, `auto`; additional valid reasoning labels are logged as a warning. For PR follow-ups, a reasoning label directly on the PR takes precedence over any reasoning label on its linked issue. Reasoning labels do not expand the job matrix, so an issue with multiple `base-*` or `llm-*` labels still creates the same number of jobs, with the selected reasoning level stamped onto each child job. ## Job Creation -When the daemon finds eligible work, it creates BullMQ jobs in Redis containing: +When the daemon finds an eligible issue, it creates one parent `processGitHubIssue` job in Redis containing the repository owner/name, issue number, triggering label, triggering user, and correlation metadata. The parent job ID is deterministic: -- Repository owner/name -- Issue or PR number -- Trigger type -- Base branch context -- Selected model or model label -- Optional per-issue reasoning level override -- Correlation metadata for logs and task records +```text +issue--- +``` -For multi-model issue processing, the daemon creates one job per model label so each result can be tracked independently. Each job gets a deterministic ID: +A worker runs the parent job as a dispatcher: it reads the issue's current labels, resolves the `base-*` and `llm-*` labels and any reasoning level override, and enqueues one child job per base branch × model so each result can be tracked independently. Child jobs also get deterministic IDs: ```text -issue----- +issue------ ``` ## Deduplication -Deterministic job IDs are the primary deduplication mechanism: enqueueing the same issue/agent/model combination again is a no-op while the original job exists. The daemon also checks state labels and task state before enqueueing, which prevents repeated processing when polling sees the same issue across multiple cycles, or when a webhook event arrives for an issue that is already being processed. +Deterministic job IDs are the primary deduplication mechanism: enqueueing the same issue, or the same issue/agent/model/base combination, again is a no-op while the original job exists. The daemon also checks state labels and task state before enqueueing, which prevents repeated processing when polling sees the same issue across multiple cycles, or when a webhook event arrives for an issue that is already being processed. ## Relationship To Workers @@ -135,7 +130,7 @@ POLLING_INTERVAL_MS=60000 # Label configuration PRIMARY_PROCESSING_LABELS=AI,propr MODEL_LABEL_PATTERN=^llm-(.+)$ -DEFAULT_MODEL_NAME= +DEFAULT_CLAUDE_MODEL= # Event intake mode: routing_websocket (default), polling, or direct_webhook. # GH_WEBHOOK_SECRET applies only to direct_webhook (your own GitHub App). diff --git a/docs/docs/architecture/git-management.md b/docs/docs/architecture/git-management.md index 480c39ce2..cd853e08b 100644 --- a/docs/docs/architecture/git-management.md +++ b/docs/docs/architecture/git-management.md @@ -53,7 +53,7 @@ Branches are generated with task and model information so the result can be trac For example: ```text -142/claude-opus5-fix-empty-state-20260612-0915-a3f2 +142/claude-opus-5-5-fix-empty-state-20260612-0915-a3f ``` The name combines: @@ -68,8 +68,8 @@ The name combines: Repositories can use different default branches. ProPR resolves branch settings in this order: 1. Repository-specific configuration (Web UI, or the `GIT_DEFAULT_BRANCH__` environment variable) -2. Global fallback branch (`GIT_FALLBACK_BRANCH`, default `main`) -3. Repository provider default, where available +2. Repository provider default (GitHub API, then the clone's remote `HEAD`) +3. Global fallback branch (`GIT_FALLBACK_BRANCH`, default `main`), then common names such as `master` and `develop` that exist on the remote Planner Studio and issue automation should use the configured repository entry rather than asking each user to type branch names manually. diff --git a/docs/docs/architecture/git-runtime.md b/docs/docs/architecture/git-runtime.md index a71d93a10..e7c5e44bb 100644 --- a/docs/docs/architecture/git-runtime.md +++ b/docs/docs/architecture/git-runtime.md @@ -34,7 +34,7 @@ GIT_SHALLOW_CLONE_DEPTH= Retry behavior for transient git failures is hard-coded (exponential backoff in `retryHandler.ts`) and is not environment-configurable. -For image-based installs, paths should point inside the ProPR containers and be backed by the host directory passed to the launcher through `PROPR_REPOS_DIR`. +For image-based installs, keep the defaults. The launcher mounts the host's `/tmp/git-processor` into the ProPR containers at the same path, and agent containers bind-mount worktrees by that path, so clones and worktrees must stay under `/tmp/git-processor`. ## Directory Setup @@ -45,7 +45,7 @@ mkdir -p /tmp/git-processor/{clones,worktrees} chmod 755 /tmp/git-processor ``` -Image-based installs usually do not require this manual step because the launcher mounts the runtime repository directory into the containers. +Image-based installs usually do not require this manual step because the launcher mounts `/tmp/git-processor` from the host into the containers. ## Worktree Operations diff --git a/docs/docs/architecture/preview-storage-relay.md b/docs/docs/architecture/preview-storage-relay.md index 1c2c50c70..6be5933ca 100644 --- a/docs/docs/architecture/preview-storage-relay.md +++ b/docs/docs/architecture/preview-storage-relay.md @@ -80,3 +80,7 @@ again. Staged evidence retains its task ID for existing publication callers. Failures are isolated per asset, including local file errors and unavailable or disabled storage. Codes are a bounded union (`PreviewStorageErrorCodeV1`, +`plus_required`, or `disabled`); raw remote errors are discarded. A failed asset +does not discard successful results or stop later uploads or GitHub publication. +Only these codes may be used for fallback text. Never log or publish upload grants, +object keys, relay tokens, or raw remote response/error bodies. diff --git a/docs/docs/architecture/worker-runtime.md b/docs/docs/architecture/worker-runtime.md index 4b1237d19..c0a3c39c8 100644 --- a/docs/docs/architecture/worker-runtime.md +++ b/docs/docs/architecture/worker-runtime.md @@ -80,7 +80,7 @@ ANTIGRAVITY_TIMEOUT_MS=86400000 OPENCODE_TIMEOUT_MS=86400000 VIBE_TIMEOUT_MS=86400000 -# Git paths (defaults shown; override for image-based installs) +# Git paths (defaults shown; keep them for image-based installs) GIT_CLONES_BASE_PATH=/tmp/git-processor/clones GIT_WORKTREES_BASE_PATH=/tmp/git-processor/worktrees ``` diff --git a/docs/docs/architecture/worker.md b/docs/docs/architecture/worker.md index b6e4b11d2..acf15da55 100644 --- a/docs/docs/architecture/worker.md +++ b/docs/docs/architecture/worker.md @@ -77,11 +77,12 @@ If the agent made no changes, the worker records that result instead of creating The worker registers BullMQ processors for several job names: -- `processGitHubIssue` — labeled GitHub issues and Planner Studio implementation tasks +- `processGitHubIssue` — labeled GitHub issues and Planner Studio implementation tasks (a parent job fans out one child job per base branch × model) - `processPullRequestComment` — PR follow-up comments and AI review/fix commands - `processTaskImport` — task imports - `processSystemTask` — signed system tasks such as reverts and recovery actions - `processMergeConflict` — merge and conflict-resolution commands +- `processGoal` — long-running [goal](../features/goals.md) sessions Separate `analysis-worker` and `indexing-worker` services handle repository analysis and indexing jobs so heavy implementation work does not block them. diff --git a/docs/docs/concepts/repository-best-practices.md b/docs/docs/concepts/repository-best-practices.md index caf8c23ab..51134d1bd 100644 --- a/docs/docs/concepts/repository-best-practices.md +++ b/docs/docs/concepts/repository-best-practices.md @@ -11,7 +11,7 @@ Run lint, type checks, tests, and the build on every pull request through GitHub Two ProPR features consume CI results directly, so CI is not just a reviewer aid — it changes how automation behaves: - **Auto-merge** (`--auto-merge`, or the `auto-merge` label) enables GitHub's native auto-merge, which holds the merge until all **required** status checks and approvals pass. This is only as safe as your branch protection: if no checks are marked *required*, auto-merge can merge as soon as the PR is mergeable. Define required status checks in [branch protection](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches) so auto-merge waits for them. See [`--auto-merge`](../features/propr-cli.md) and [Planner Studio](../tutorials/planner-studio.md). -- **`/ultrafix`** defers its next review/fix cycle until checks are passing and resumes when a `check_run` completes. Fast, reliable CI means tighter cleanup loops; slow or flaky CI stalls them. Note that a commit with *no* check runs is treated as ready, so `/ultrafix` only benefits from CI when checks actually exist. See [`/ultrafix`](../features/pr-commands.md#ultrafix). +- **`/ultrafix`** waits for passing checks before each re-review and resumes when a `check_run` completes. Fast, reliable CI means tighter cleanup loops; slow or flaky CI stalls them. Note that a commit with *no* check runs is treated as ready, so `/ultrafix` only benefits from CI when checks actually exist. See [`/ultrafix`](../features/pr-commands.md#ultrafix). Practical implications: keep CI **fast** (loops and merges wait on it) and **deterministic** — flaky tests stall `/ultrafix`, block auto-merge, and can send fix loops chasing failures that aren't real. diff --git a/docs/docs/concepts/security-overview.md b/docs/docs/concepts/security-overview.md index 4491f11a2..90660788a 100644 --- a/docs/docs/concepts/security-overview.md +++ b/docs/docs/concepts/security-overview.md @@ -13,7 +13,7 @@ ProPR is self-hosted: the delivery layer, task history, credentials, and reposit | --- | --- | --- | | **Your ProPR stack** | Everything: repository clones, plans, prompts, task records, logs, usage data, credentials | — | | **GitHub** | Branches, commits, pull requests, comments, labels, status checks | Plans, task logs, provider credentials | -| **Selected model provider** | The prompt and code context for the specific task routed to it | Unrelated repositories, other providers' credentials, the task archive | +| **Selected model provider** | The prompt and code context for the specific task routed to it, plus whatever the agent reads inside its container | Other providers' credentials, the task archive | | **ProPR Connect** (optional) | GitHub webhook payloads it relays, plus the installation metadata needed to route and bill them | Repository contents. Successful deliveries are not stored; failed deliveries are cached briefly for replay | Model calls go directly from your stack to the provider you configured. ProPR is not a proxy for LLM traffic and never sees or marks up your tokens. @@ -24,7 +24,9 @@ Model calls go directly from your stack to the provider you configured. ProPR is Every implementation task runs in its own Docker container and its own Git worktree on a dedicated branch. The agent edits files; it does not commit, push, or open PRs — ProPR performs those Git and GitHub operations deterministically after the agent finishes. The main checkout is never touched, and a wrong result is contained to a branch you can review, retry, or discard. Details: [Execution Safety](../features/execution-safety.md). -Outbound network access from agent containers is **unrestricted by default**. An optional allowlist firewall (model provider, GitHub, DNS only) ships in the unified agent image but is off by default because it requires privileged containers — do not assume network sandboxing unless you enabled it. +The container isolates the workspace; it does not keep ProPR's GitHub access or other clones away from the agent. Implementation containers receive a GitHub installation token (`GH_TOKEN`) with the installation's permissions, so the no-push rule is enforced by the workflow instructions rather than by token scope. Most agents also mount the shared git directory that holds every repository clone on the host, so an agent can read other repositories ProPR has cloned. Run repositories with different trust levels on separate stacks. + +Outbound network access from agent containers is **unrestricted by default**. An optional allowlist firewall (Anthropic API, GitHub, DNS, and outbound SSH only) ships in the unified agent image but is off by default because it requires privileged containers, and its allowlist covers only Claude Code's provider — do not assume network sandboxing unless you enabled it. The API and worker use the host Docker socket to launch task containers; the API also uses it for authenticated agent-login sessions. Docker-socket access is root-equivalent control of the host. Treat the API container as part of the trusted control plane, restrict dashboard access, and do not expose the socket to unrelated containers. Login sessions run only the provider-specific allowlisted command in the configured agent image, keep output in memory, and remove their temporary container on completion, cancellation, timeout, graceful shutdown, or the next API startup after a crash. @@ -66,14 +68,14 @@ Configuration lives in the Web UI settings and `.env` — see [GitHub Authentica ## Secrets And Credentials -- **`.env` in the stack root** holds deployment secrets; it is mounted read-only into containers. +- **`.env` in the stack root** holds deployment secrets; it is mounted read-only into the service containers, not into agent containers. - **Agent credentials** are mounted read-write so agent CLIs can refresh their own auth state. Direct-login accounts are isolated by agent ID below ProPR's managed credential root (`~/.propr/agent-credentials` for native/Compose installs or the launcher data directory); reused host accounts keep their configured paths (`~/.claude`, `~/.codex`, `~/.gemini`, …). - **GitHub access**: on the default relay path your stack holds a revocable relay token and mints short-lived installation tokens — no GitHub App private key on disk. On the own-App path, the private key stays on your host. - **Tunnel token**: `PROPR_UI_TUNNEL_TOKEN` is a live Cloudflare credential — keep it in `.env` only. ## Data At Rest -Application state lives in the stack directory on your host: the database under `data/`, logs under `logs/`, repository clones and worktrees under `repos/`, and queue state in the Redis volume. Direct-login credentials live in the managed credential root, which is below `~/.propr` for native/Compose installs or below the launcher data directory. Treat that root as persistent secret data when backing up or removing a deployment — see [Teardown](../operations/maintenance.md#teardown). +Application state lives in the stack directory on your host: the database under `data/`, logs under `logs/`, and queue state in the Redis volume. Repository clones and task worktrees live on the host under `/tmp/git-processor` by default (`GIT_CLONES_BASE_PATH`, `GIT_WORKTREES_BASE_PATH`). Direct-login credentials live in the managed credential root, which is below `~/.propr` for native/Compose installs or below the launcher data directory. Treat that root as persistent secret data when backing up or removing a deployment — see [Teardown](../operations/maintenance.md#teardown). ## Connected clients and private media diff --git a/docs/docs/faq.md b/docs/docs/faq.md index b91676a07..d8bd30796 100644 --- a/docs/docs/faq.md +++ b/docs/docs/faq.md @@ -24,7 +24,7 @@ A terminal session needs you at the keyboard, approving commands and edits as th Each task runs in its own Docker container and Git worktree, and ProPR itself performs all Git and GitHub operations on the agent's behalf. Outbound network access is unrestricted by default; an optional allowlist firewall exists but requires privileged containers. See [Execution Safety](./features/execution-safety.md). **Can I run it offline or air-gapped?** -No. ProPR needs GitHub and your model providers to do its job. The documentation is bundled for offline reading (`propr docs`), but the workflow itself is GitHub-centered. +No. ProPR needs GitHub and your model providers to do its job. The documentation is bundled for offline reading (`propr docs on`), but the workflow itself is GitHub-centered. **Does it work with GitLab or Bitbucket?** No — the whole loop is built on GitHub's APIs: pull requests, review comments, checks, and comment commands. @@ -36,4 +36,4 @@ The task record keeps the prompt, logs, and failure state; issues get `AI-failed A user whitelist gates the dashboard, the CLI, and GitHub-triggered work; bots are filtered; PR commands run only for allowed authors. See [Who Can Trigger Work](./concepts/security-overview.md#who-can-trigger-work). **Where is my data stored, and how do I remove it?** -In the stack directory on your host (`data/`, `logs/`, `repos/`, plus the Redis volume). The [Teardown guide](./operations/maintenance.md#teardown) lists every artifact to remove. +In the stack directory on your host (`data/`, `logs/`, `repos/`), the Redis volume, and repository clones and worktrees under `/tmp/git-processor` by default. The [Teardown guide](./operations/maintenance.md#teardown) lists every artifact to remove. diff --git a/docs/docs/features/agents-and-models.md b/docs/docs/features/agents-and-models.md index e8f3fd06c..57a9e3f74 100644 --- a/docs/docs/features/agents-and-models.md +++ b/docs/docs/features/agents-and-models.md @@ -4,7 +4,7 @@ sidebar_position: 5 # Agents and Models -ProPR runs coding work through configurable agents. Each agent is a CLI tool packaged in its own Docker image, with an isolated credential directory mounted into that image. Models are addressed by stable ProPR model IDs that work everywhere a model can be chosen: issue labels, the Web UI, the CLI (`-a`/`-m`), and PR commands (`/switch`, `/use`, `/review `). +ProPR runs coding work through configurable agents. Each agent is a CLI tool that runs in the unified `propr/agent` Docker image, with an isolated credential directory mounted into its container. Models are addressed by stable ProPR model IDs that work everywhere a model can be chosen: issue labels, the Web UI, the CLI (`-a`/`-m`), and PR commands (`/switch`, `/use`, `/review `). The canonical catalog lives in `packages/shared/src/modelDefinitions.ts`. The tables below reflect that file; if they ever disagree, the source file wins. Custom model IDs can also be added per agent in the Web UI (**AI Agents**) or with `propr agent add`. diff --git a/docs/docs/features/branch-config.md b/docs/docs/features/branch-config.md index daa86056b..eab39eb88 100644 --- a/docs/docs/features/branch-config.md +++ b/docs/docs/features/branch-config.md @@ -25,7 +25,7 @@ That issue run targets `release/2026`. Multiple `base-` labels create one run per base branch. Combined with multiple `llm-*` model labels, ProPR fans out one job per base × model combination. -If no `base-` label is present, ProPR detects the default branch for the repository (see resolution order below). +If no `base-` label is present, the run targets the repository's default branch as reported by GitHub. If the requested base branch does not exist on the remote, ProPR falls back to default-branch detection (see resolution order below). ## Default Branch Resolution Order @@ -69,4 +69,5 @@ Check: - The variable name matches the owner and repo (uppercased, non-alphanumeric characters replaced by `_`). - The branch exists on the remote — a configured branch that does not exist is skipped and detection falls through to the GitHub API. +- The run has no explicit base branch. Labeled issues without a `base-` label use GitHub's default branch directly and consult the override only when that branch is missing on the remote. - The relevant containers were restarted after `.env` changed. diff --git a/docs/docs/features/execution-safety.md b/docs/docs/features/execution-safety.md index 4ab4bdca2..e681aab79 100644 --- a/docs/docs/features/execution-safety.md +++ b/docs/docs/features/execution-safety.md @@ -23,7 +23,7 @@ This makes concurrent work possible across issues, PR comments, and models witho Worker execution is split into three phases. The agent only participates in the middle one: 1. **Pre-agent setup (ProPR)**: pull the job from the queue, update the base branch, create the isolated git worktree, create the task branch, and prepare the prompt and context. -2. **Agent implementation (agent)**: run the selected agent inside its container against the worktree. The agent edits files; it does not push, create branches, or open pull requests. +2. **Agent implementation (agent)**: run the selected agent inside its container against the worktree. The agent edits files; its instructions tell it not to commit, push, create branches, or open pull requests, because ProPR does that next. 3. **Post-agent finalization (ProPR)**: inspect changed files, commit, push to GitHub, create or update the pull request with issue linking, and update labels and task state. Because the git and GitHub steps are deterministic code rather than agent decisions, branch mistakes are rare and failures are easier to attribute: a failure in phase 1 or 3 is a git/GitHub problem, a failure in phase 2 is an agent problem. @@ -51,14 +51,17 @@ Branch names include the model identifier, so concurrent multi-model runs never Each agent run starts a dedicated container from the unified `propr/agent` image. The container gets: - The task worktree mounted as its working directory -- The agent credential directories mounted read-write from the host at their original paths (for example `~/.claude`, `~/.codex`, `~/.gemini`) so CLIs can refresh auth state; only the `.env` file is mounted read-only +- The agent's credential directory (for example `~/.claude`, `~/.codex`, `~/.gemini`) mounted read-write into the container's home so the CLI can refresh auth state (Vibe's config is mounted read-only) +- For most agents, the shared git directory (`/tmp/git-processor`, which holds every repository's clone and worktrees) so git works inside the linked worktree +- On implementation runs, a GitHub installation token as `GH_TOKEN`, so the agent can read issue and PR context with `gh`; the token carries the GitHub App installation's permissions, so the no-push rule is a workflow instruction rather than a permission boundary +- Memory, CPU, and process limits (defaults `6g`, up to 4 CPUs, and 512 PIDs; override with `AGENT_CONTAINER_MEMORY_LIMIT`, `AGENT_CONTAINER_CPU_LIMIT`, `AGENT_CONTAINER_PIDS_LIMIT`) and the `no-new-privileges` security option - A per-agent timeout (`CLAUDE_TIMEOUT_MS`, `CODEX_TIMEOUT_MS`, `ANTIGRAVITY_TIMEOUT_MS`, `OPENCODE_TIMEOUT_MS`, `VIBE_TIMEOUT_MS`) The image-based install starts service and agent containers from published images. Source builds can use local images during development. ## Network Firewall (Optional, Off By Default) -The unified agent image ships `scripts/init-firewall.sh`, an iptables script that drops all traffic except loopback, DNS, SSH, and HTTPS to provider and GitHub endpoints (for example `api.anthropic.com`, `api.github.com`, `github.com`, `objects.githubusercontent.com`). +The unified agent image ships `scripts/init-firewall.sh`, an iptables script that drops all traffic except loopback, DNS, outbound SSH, and HTTPS to `api.anthropic.com`, `api.github.com`, `github.com`, and `objects.githubusercontent.com`. Its allowlist has no entries for OpenAI, Google, OpenCode providers, or Mistral, so enabling it as shipped would block every agent except Claude Code. The script is **not executed by default**. Every agent entrypoint (`scripts/claude-entrypoint.sh`, `codex-entrypoint.sh`, `antigravity-entrypoint.sh`, `opencode-entrypoint.sh`, `vibe-entrypoint.sh`) currently skips it and logs: diff --git a/docs/docs/features/goals.md b/docs/docs/features/goals.md index 9088fdd4c..88f5007da 100644 --- a/docs/docs/features/goals.md +++ b/docs/docs/features/goals.md @@ -15,9 +15,9 @@ Synthetic pools cannot run goals. Availability is also checked against the confi ## Start and monitor a goal -1. Open **Goals**, choose **New Goal**, then select a repository and a goal-capable agent/model. -2. Choose a launch strategy (see below) and, optionally, the maximum number of parallel tasks and whether the agent runs Ultrafix before it finishes. -3. Enter the objective and attach supporting material. Respect the character limit shown for the selected provider. Start the goal and open it from the work queue. +1. Open **Goals**, choose **New Goal**, then select a repository. +2. Enter the objective in **Prompt** and attach supporting material. Respect the character limit shown for the selected provider. +3. Under **Advanced Options**, choose a goal-capable agent and model, a launch strategy (see below) and, optionally, the maximum number of parallel tasks and whether the agent runs Ultrafix before it finishes. Choose **Start goal** and open it from the work queue. ![Goals work queue showing an active analytics goal and a completed billing goal with status and progress](/img/screenshots/0.9.0/goals.png) @@ -25,9 +25,9 @@ The detail console brings together context, current activity, progress, artifact ## Launch strategies -**Agent implements directly.** The agent works in the goal workspace. ProPR opens a draft PR on the goal branch and owns every commit and push. When a coherent set of changes is ready, the agent requests a checkpoint; ProPR validates the listed paths, commits only that scope, pushes, records the commit and publishes current visual previews to the draft PR. The checkpoint cadence defaults to roughly every 15 minutes. It is guidance to the agent, not a timer that interrupts it. +**Direct** (agent implements directly). The agent works in the goal workspace. ProPR opens a draft PR on the goal branch and owns every commit and push. When a coherent set of changes is ready, the agent requests a checkpoint; ProPR validates the listed paths, commits only that scope, pushes, records the commit and publishes current visual previews to the draft PR. The **Checkpoint target cadence** defaults to roughly every 15 minutes and can be set from 5 to 120 minutes. It is guidance to the agent, not a timer that interrupts it. -**Agent orchestrates through ProPR.** The agent decides how to break the objective down, creates GitHub issues, and starts and monitors their implementation through ProPR, optionally building an epic PR from the resulting PRs. It must track every issue and PR it creates and finish with a validated draft PR containing the final implementation. +**Orchestrate through ProPR.** The agent decides how to break the objective down, creates GitHub issues, and starts and monitors their implementation through ProPR, optionally building an epic PR from the resulting PRs. It must track every issue and PR it creates and finish with a validated draft PR containing the final implementation. In both strategies, **max parallel tasks** is a limit the agent enforces itself; ProPR does not schedule a plan graph for goals. With **Ultrafix** enabled, the agent runs Ultrafix as part of delivery before declaring the goal complete; with it disabled, the agent runs Ultrafix only if a later correction asks for it. diff --git a/docs/docs/features/launching-work.md b/docs/docs/features/launching-work.md index 7a0492090..4f76ab63d 100644 --- a/docs/docs/features/launching-work.md +++ b/docs/docs/features/launching-work.md @@ -5,14 +5,14 @@ Use **New Task** for one bounded change, **New Plan** when you want to review a ## Start a task 1. Open **New Task** (`/tasks/new`) and select an enabled repository. -2. Enter the **Instruction** with the intended result and acceptance criteria. Attach relevant files if needed, and choose agent/model routing when overriding the default. +2. Enter the **Prompt** with the intended result and acceptance criteria. Attach relevant files if needed (up to 10), and choose an agent and model under **Advanced Options** when overriding the default. **Plan first** opens the same request in Planner Studio instead. 3. Choose **Run task**. ProPR creates a GitHub issue and submits the ordinary implementation task. Follow the linked task for progress and its resulting PR. ![New task form with a repository, invoice formatting instruction and Run task action](/img/screenshots/0.9.0/new-task.png) The repository workspace's **New task** action prefills the repository. Select a to-do and choose **Run task** to prefill its text; launching does not mark the to-do complete. Submission acceptance is not implementation completion. If submission reports a failure or uncertain issue creation, use the displayed recovery action instead of starting duplicate requests. -MCP clients can use `create_task` with execute scope and a stable idempotency key; see [MCP](./mcp.md). The CLI's existing issue implementation and `task inspect` commands are described in [CLI workflows](./cli-workflows.md). +MCP clients can use `create_task` with execute scope and a stable idempotency key, then follow the task and its pull request with `get_task_submission`; see [MCP](./mcp.md). The CLI's existing issue implementation and `task inspect` commands are described in [ProPR CLI](./propr-cli.md#issue-implementation). ## Plan or goal? diff --git a/docs/docs/features/mcp-chat.md b/docs/docs/features/mcp-chat.md index e2113273c..0e942cfee 100644 --- a/docs/docs/features/mcp-chat.md +++ b/docs/docs/features/mcp-chat.md @@ -13,5 +13,6 @@ MCP must be enabled and configured on the instance first. Client support varies, - Ask what is running, queued, or blocked across the authorized repositories. - Ask for details about a task or pull request before deciding on the next action. - Request a new task, a review, or a fix with the appropriate permissions, then check its progress. An accepted task is not yet completed work. +- Ask what you started in the last hour and whether it finished, or ask how a ProPR feature or setting works. Use [the MCP access log](./web-ui.md#mcp-access-log) to inspect the assistant's calls. Manage or revoke direct instance connections at `/mcp/apps` on your instance. diff --git a/docs/docs/features/mcp.md b/docs/docs/features/mcp.md index b60b932ec..f30f6fb11 100644 --- a/docs/docs/features/mcp.md +++ b/docs/docs/features/mcp.md @@ -1,6 +1,6 @@ # MCP Connections and Operator Tools -MCP lets a connected coding or chat client inspect and operate ProPR using scoped authorization. It is disabled by default. Administrators use **Settings → Integrations → MCP Server** to manage enablement and the allowed scope ceiling. The UI-managed path derives an HTTPS origin and encryption key from existing instance configuration and persists an instance identity. An explicit `MCP_ENABLED=true` selects environment-managed configuration; `false` prevents UI enablement. Missing configuration is shown as a setup problem; demo mode cannot enable MCP. +MCP lets a connected coding or chat client inspect and operate ProPR using scoped authorization. It is disabled by default. Administrators use **Settings → Integrations → MCP Server** to manage enablement and the allowed scope ceiling (default: `read`, `plan`, `review`). The UI-managed path derives an HTTPS origin and encryption key from existing instance configuration and persists an instance identity. An explicit `MCP_ENABLED=true` selects environment-managed configuration, where the settings page shows the status but no toggle or ceiling; `false` prevents UI enablement. Missing configuration is shown as a setup problem; demo mode cannot enable MCP. ![MCP server settings with enablement, public endpoint and scope controls](/img/screenshots/0.9.0/mcp-settings.png) @@ -21,11 +21,15 @@ Open **Connected apps** (`/mcp/apps`) to inspect grants and revoke access. The l | Need | Tools | | --- | --- | | Current work and blockers | `get_current_activity` | +| Tasks joined to their pull request's head, review, checks and ultrafix state | `get_work_overview` | | Finished work in a recent window | `get_recent_activity` (up to seven days) | | Goal progress and corrections | `get_goal`, `list_goal_inputs` | | Tasks or goals by lifecycle | `list_tasks`, `list_goals` with `state` and optional `repository` | | Plans by status | `list_plans` with `status`: `active`, an exact persisted status, or `all` (default) | | Start a bounded change | `create_task`, then `get_operation` or `get_task_submission` | +| Find what you started and whether it finished | `list_operations`, then `get_operation` | | PR inventory and review fixes | `list_pull_requests`, `fix_review_findings` with `findingIds` and/or `suggestionIds` | +| Visual previews published for a task or PR (images; videos are metadata only) | `list_visual_previews`, `get_visual_preview` | +| Product docs and where a setting lives | `search_docs`, `get_doc`, `find_setting` | -Mutations require their corresponding scopes and repository access, and return durable receipts. Queue acceptance is not completion. Keep idempotency keys stable when retrying the same request. See the [full operator/setup reference](https://github.com/integry/propr/blob/main/docs/mcp.md) and [tool coverage](https://github.com/integry/propr/blob/main/docs/mcp-coverage.md) for schemas, Connect registration and deployment requirements. +Mutations require their corresponding scopes and repository access, and return durable receipts. Queue acceptance is not completion. Keep idempotency keys stable when retrying the same request, and repeat its arguments exactly. Failures return a structured error with a stable `code`, the `stage` where it failed and whether it is `retryable`. See the [full operator/setup reference](https://github.com/integry/propr/blob/main/docs/mcp.md) and [tool coverage](https://github.com/integry/propr/blob/main/docs/mcp-coverage.md) for schemas, Connect registration and deployment requirements. diff --git a/docs/docs/features/observability.md b/docs/docs/features/observability.md index 406a4ac3a..a60a02587 100644 --- a/docs/docs/features/observability.md +++ b/docs/docs/features/observability.md @@ -29,7 +29,7 @@ The task detail view exposes progress during execution, including streamed outpu ## Provider Capacity -With the optional [Agent Tank](../operations/agent-tank.md) integration enabled, provider capacity becomes a visible signal too: the sidebar shows live usage bars per subscription provider, and each LLM log entry records the usage delta its call consumed. Turn it on from the dashboard banner, from **Settings → LLM Usage Tracking**, or with `propr tank bundled` — bundled mode runs Agent Tank inside the ProPR agent image, so there is nothing to install. +With the optional [Agent Tank](../operations/agent-tank.md) integration enabled, provider capacity becomes a visible signal too: the sidebar shows live usage bars per subscription provider, and each LLM log entry records the usage delta its call consumed. Turn it on from the dashboard banner, from **Settings → Integrations → LLM Usage Tracking**, or with `propr tank bundled` — bundled mode runs Agent Tank inside the ProPR agent image, so there is nothing to install. ## Recovery diff --git a/docs/docs/features/planning.md b/docs/docs/features/planning.md index 06475c237..b5db4f823 100644 --- a/docs/docs/features/planning.md +++ b/docs/docs/features/planning.md @@ -21,7 +21,7 @@ Planner Studio moves a draft through three stages, shown in the stepper at the t 1. **Define & Context** — enter the request, select the repository (and with it the configured base branch), choose the planning model, adjust the context level, and attach files. ProPR previews gathered context and an estimated issue count before generation. 2. **Review Plan** — inspect the generated issues, edit or delete individual items, restore deleted ones, undo and redo edits, and send the plan back through refinement chat with follow-up instructions. -3. **Execution** — after the plan is finalized into GitHub issues, track each issue's status (Pending, Processing, Under Review, Merged), pause or resume execution, and open the resulting pull requests. +3. **Execution** — after the plan is finalized into GitHub issues, track each issue's status (Pending, Processing, Review, Merged), pause or resume execution, and open the resulting pull requests. A draft can be reset back to setup if the inputs were wrong, which makes planning useful for exploratory work as well as well-defined tickets. @@ -29,7 +29,7 @@ A generated plan is saved only when every issue has a title, a body and an imple ## Revision history and refinement -Open **Plan history** in the plan editor to inspect the plan saved before each generation, refinement or edit. Select a version to preview its tasks, then choose **Restore this version**. Restoring also saves the current plan in history. This persistent history is separate from the editor's immediate undo/redo controls and does not undo already-created GitHub issues or code changes. +Open **Plan history** in the plan editor to inspect the plan saved before each generation, refinement, edit or rename. Each version is labeled with how it was created (**Generated**, **Refined**, **Manual edit**, **Restored** or **Renamed**; older versions show **Legacy**), and edits made within a few minutes of each other share one version. History keeps the latest 50 versions. Select a version to preview its tasks, then choose **Restore this version**. Restoring also saves the current plan in history. This persistent history is separate from the editor's immediate undo/redo controls and does not undo already-created GitHub issues or code changes. Refinement returns the complete plan, including unchanged tasks, so review the full result before finalizing. Generation uses a structured file output and rejects incomplete issues rather than silently accepting a partial plan. Setup prompts auto-save; returning to setup lets you change context before regenerating. diff --git a/docs/docs/features/pr-commands.md b/docs/docs/features/pr-commands.md index 0983bf3dd..05ec0f520 100644 --- a/docs/docs/features/pr-commands.md +++ b/docs/docs/features/pr-commands.md @@ -11,7 +11,7 @@ Slash commands are for specific actions: AI review, applying AI review feedback, ## Works On Any Pull Request -You can run `/review`, `/fix`, and the others on any eligible pull request — including ones opened by a teammate, another agent, or yourself outside ProPR — as long as you are an allowed author. A slash command from an allowed author is processed directly and does not require the PR to carry a processing label. +You can run `/review`, `/fix`, and the others on any eligible pull request — including ones opened by a teammate, another agent, or yourself outside ProPR — as long as you are an allowed author. A slash command from an allowed author is processed directly and does not require the PR to carry a processing label; the exception is `/merge`, which only runs on PRs that carry one. To **take over an existing PR** for ongoing work (so that natural follow-up comments are picked up alongside commands), add a configured processing label such as `AI` or `propr` to the PR. See [Use ProPR On Any Pull Request](./pr-followup.md#use-propr-on-any-pull-request). @@ -35,19 +35,19 @@ To **take over an existing PR** for ongoing work (so that natural follow-up comm ## Model IDs -Commands that take a model accept the model IDs configured in AI Agents. The `llm-` prefix is optional in command arguments — `/switch claude-opus5` and `/switch llm-claude-opus5` are equivalent. Unrecognized models are rejected. The built-in catalog is listed in [Agents and Models](./agents-and-models.md). +Commands that take a model accept the model IDs configured in AI Agents. The `llm-` prefix is optional in command arguments — `/switch claude-opus5` and `/switch llm-claude-opus5` are equivalent. `/switch` and `/use` ignore a model that is neither in the catalog nor configured on an enabled agent; `/review` skips models it cannot resolve and fails only when none of the requested models resolve. The built-in catalog is listed in [Agents and Models](./agents-and-models.md). ## Who Can Trigger Commands ProPR filters PR comments by author before processing anything (commands and natural follow-ups alike): -- Bot accounts (usernames containing `[bot]` or with user type `Bot`) and ProPR's own bot account are ignored by default. To exempt a bot, add its exact `name[bot]` login to the GitHub User Whitelist in Settings or use the MCP `update_trigger_access_configuration` tool's `addBots` operation. -- If `GITHUB_USER_WHITELIST` is set (comma-separated usernames), only those users can trigger processing. Environment-managed entries are read-only through MCP. -- Users listed in `GITHUB_USER_BLACKLIST` are ignored. +- Bot accounts (usernames containing `[bot]` or with user type `Bot`) and ProPR's own bot account are ignored by default. +- The GitHub User Whitelist (Settings, or `GITHUB_USER_WHITELIST` as comma-separated logins) is exclusive: when it has any entries, **only** listed users and bots can trigger processing, and the bot and blacklist checks are skipped for them. Matching ignores a `[bot]` suffix, so `name` also admits `name[bot]`. To exempt a bot, add it to the whitelist in Settings or with the MCP `update_trigger_access_configuration` tool's `addBots` operation — and add every human who should keep access, because adding one bot to an empty whitelist blocks everyone else. Environment-managed entries are read-only through MCP. +- Users listed in `GITHUB_USER_BLACKLIST` are ignored when no whitelist is set. - MCP administrators with `instance.manage_settings` can inspect all three lists with `get_trigger_access_configuration`. User and bot allowlist changes use `update_trigger_access_configuration`; the environment-only blocklist is reported but cannot be edited by the tool. - Comments containing a configured follow-up ignore keyword are skipped. -Slash commands from an allowed author are processed directly. Natural follow-up comments are additionally gated: the PR must carry one of the configured processing labels (for example `AI` or `propr`), or the comment must contain a trigger keyword from `PR_FOLLOWUP_TRIGGER_KEYWORDS` (for example `!propr`). +Slash commands from an allowed author are processed directly. Natural follow-up comments are additionally gated: the PR must carry one of the configured processing labels (for example `AI` or `propr`), or the comment must contain a trigger keyword from `PR_FOLLOWUP_TRIGGER_KEYWORDS` (for example `!propr`). When `PR_FOLLOWUP_TRIGGER_KEYWORDS` is empty or unset, every comment from an allowed author triggers a follow-up, labeled PR or not. ## Review And Fix @@ -179,8 +179,10 @@ Keep the public helper signature unchanged. independently — a review with no merge blocker still continues the `S#` count. - Identifiers are read from the command line only, and are case-insensitive (`/fix f20 s3` is `/fix F20 S3`). -- Everything after the last identifier on that line, plus every following line, - is passed to the agent as instructions. The identifiers themselves are not. +- Identifiers end at the first word on that line that is not one (commas may + separate identifiers, and a `;` ends the list explicitly). That word, the rest + of the line, and every following line are passed to the agent as + instructions. The identifiers themselves are not. - An identifier no current review offers fails the whole command closed, even when other identifiers in the same request are available: nothing is applied, and ProPR names the identifiers it could not resolve on the pull request. This @@ -224,7 +226,7 @@ Use model routing commands when the current PR should use a different configured ProPR replaces the PR's `llm-*` label with the new model's label. Later comments, commands, and ultrafix cycles on this PR use the new model. -`/switch` takes exactly one model argument; extra arguments are ignored with a warning. The model must be a known catalog model or a model configured on an enabled agent — unrecognized models are rejected. +`/switch` takes exactly one model argument; extra arguments are ignored. The model must be a known catalog model or a model configured on an enabled agent — otherwise the command is ignored and the label stays unchanged. If you include instructions on the lines below the command, ProPR switches the label and also queues one follow-up run with the new model using those instructions: @@ -269,10 +271,12 @@ Post: /merge ``` -ProPR merges the base branch into the PR branch inside an isolated worktree. Merging the PR itself into the base branch remains your call — a human clicks that merge button. An agent run accompanies the branch update: +`/merge` runs only on PRs that carry a configured processing label (for example `AI` or `propr`). ProPR merges the base branch into the PR branch inside an isolated worktree. Merging the PR itself into the base branch remains your call — a human clicks that merge button. An agent run accompanies the branch update: - On a clean merge, the agent verifies the result before it is pushed. -- On conflicts, the agent resolves the conflict markers; ProPR then scans the tree to confirm no conflict markers remain before pushing. If markers remain, the task fails and the broken merge stays unpushed. +- On conflicts, the agent resolves the conflict markers. + +In both cases ProPR then scans the tree to confirm no conflict markers remain before pushing. If markers remain, the task fails and the broken merge stays unpushed. ProPR posts a status comment on the PR when the merge starts and updates it with the result. @@ -309,8 +313,8 @@ A bare number is treated as the goal: `/ultrafix 8` is the same as `/ultrafix go Before each cycle, ProPR checks readiness: -- Required CI checks must be passing; if they are not, the continuation is deferred and resumes when check results arrive. -- The PR must be inactive, so the loop does not race human pushes or comments. +- Before each review cycle, CI on the PR head must be passing (every check run and commit status, except checks the repository marks [non-blocking](./pr-followup.md#checks-that-never-block-automation)); if it is not, the continuation is deferred and resumes when check results arrive. Fix cycles do not wait for CI. +- The PR must be inactive — no other queued or running job and no pending batched comments — so the loop does not race other work on the PR. - The configured `pause` delay is applied between cycles. #### Stopping The Loop @@ -320,7 +324,7 @@ The loop is controlled by the visible `ultrafix` PR label, which acts as a circu #### Completion - **Goal reached**: the `ultrafix` label is removed. If the PR belongs to a planned issue labeled `auto-merge`, ProPR re-enables GitHub auto-merge on the PR. -- **Max cycles exhausted**: ProPR posts a warning comment with the requested goal and the last score, and manual review takes over. +- **Stopped before the goal** (max cycles exhausted, or a review that cannot advance the loop): ProPR posts a warning comment with the requested goal and the last score, and manual review takes over. The `ultrafix` label is left on the PR; remove it once you take over. Reserve `/ultrafix` for stronger cleanup passes. For small edits and direct changes, a normal PR comment is usually better. diff --git a/docs/docs/features/pr-followup.md b/docs/docs/features/pr-followup.md index 30b1d0729..182332fa1 100644 --- a/docs/docs/features/pr-followup.md +++ b/docs/docs/features/pr-followup.md @@ -60,6 +60,10 @@ For more autonomous cleanup, `/ultrafix` alternates review and fix cycles until Full syntax, parameters, and trigger rules for every command are in [PR Comment Commands](./pr-commands.md). +## Automatic Follow-Up For Failed CI + +**Auto CI follow-up** (Repositories → repository → Automation, or `propr repo toggle owner/repo --auto-ci-followup`) is off by default. When enabled, a failing check run or commit status on the current head of a pull request makes ProPR post one comment naming the check, the commit, and the failure output; that comment starts follow-up work like any other, without a processing label or trigger keyword. Each failing check is reported at most once per commit. Enable it only where CI failures are trustworthy signals. + ## Cancelling Obsolete Checks During Follow-Up While a follow-up implements, the checks running on the commit it is about to replace are already obsolete, and on a busy repository they keep runners occupied for work nobody will read. GitHub's own `cancel-in-progress` concurrency only helps once a replacement workflow starts, which is after the new commit is pushed. @@ -91,7 +95,7 @@ Some checks are worth running but should not decide whether ProPR moves a pull r A failure of a listed check: -- does not hold back auto-merge (`/merge`) or ultrafix continuation; +- does not hold back auto-merge or ultrafix continuation; - does not start an automatic failed-CI follow-up; - is shown to reviews as neutral and marked *(non-blocking)*, not as a failure of the change. diff --git a/docs/docs/features/propr-cli.md b/docs/docs/features/propr-cli.md index 4ff3cbe6c..286656224 100644 --- a/docs/docs/features/propr-cli.md +++ b/docs/docs/features/propr-cli.md @@ -28,10 +28,11 @@ Bring up a complete ProPR stack from the terminal: propr setup # guided one-time bootstrap: scaffold, verify, configure, start (re-runnable) propr init stack # scaffold .env + data/ logs/ repos/, detect agent credentials propr check # verify Docker, images, agents, and GitHub auth mode (--verify smoke-tests agents) +propr images pull # pull missing or stale images without starting the stack propr start # pull images and start the stack with a live dashboard propr status # local stack status (--json for scripts) -propr ui # open the Web UI (http://localhost:5173) -propr docs # open the bundled docs site +propr ui on|off # start or stop the Web UI service (http://localhost:5173) +propr docs on|off # start or stop the bundled docs service propr stop # stop the stack (--keep to stop without removing containers) propr tunnel on # expose the stack to the hosted UI through a Cloudflare Tunnel propr tunnel off # stop the tunnel (token and env values are kept) @@ -135,7 +136,7 @@ Configuration is stored in `~/.propr/config.json`. | Option | Description | |--------|-------------| | `-p, --project ` | Target project for this invocation (overrides `propr use`) | -| `-j, --json` | Machine-readable output (supported by most commands) | +| `-j, --json` | Machine-readable output (a per-command flag supported by most commands; a few accept only `--json`) | | `-V, --version` | Print the CLI version | | `-h, --help` | Help for any command or subcommand | @@ -181,7 +182,7 @@ propr plan delete --force # Delete without confirmation | Option | Applies to | Description | |--------|-----------|-------------| -| `-b, --branch` | `create` | Target branch (default: the repo's configured default) | +| `-b, --branch` | `create` | Target branch (default: `main`) | | `-w, --wait` | `create`, `generate` | Block until plan generation completes | | `-f, --force` | `delete` | Skip the confirmation prompt | @@ -216,7 +217,9 @@ propr task inspect # Current details and full run histor propr task get # Details with run history propr task stop # Stop a running task propr task delete --force # Force-delete an active task -propr task revert owner/repo # Revert a commit from a PR +propr task followup "Also add tests" # Post and queue a follow-up (or --file / --stdin) +propr task import "Recover missing tasks" # Reconcile or recover tasks from GitHub +propr task revert owner/repo [comment-id] # Revert a commit from a PR (--dry-run to preview) ``` Status values for `-s`: `pending`, `queued`, `processing`, `completed`, `failed`, `cancelled`, `all`. These are queue-level filters; task details additionally display the finer-grained worker states `claude_execution` ("Executing", agent run for any agent type) and `post_processing` (see [Worker Runtime](../architecture/worker-runtime.md)). @@ -337,12 +340,22 @@ Settings keys: | `planner_generation_model` | Model for planner generation | | `auto_followup_score_threshold` | Score threshold (0–9) for auto-followup | | `auto_resolve_merge_conflicts` | Automatically resolve merge conflicts | +| `dashboard_summary_enabled` | Enable AI-generated dashboard activity summaries | +| `model_reasoning_level` | Reasoning level for GPT and Claude agents (empty = agent default) | +| `usage_tips_enabled` | Show daily documentation tips on the dashboard | +| `usage_tips_dismissal_cooldown_days` | Base dismissal cooldown for tips (1–365 days) | | `pr_review_model` | Model for full PR reviews | | `pr_review_prompt` | Override for the PR review prompt guidance (empty = built-in default) | +| `pr_review_context_enabled` | Gather related unchanged code before PR reviews | +| `pr_review_context_model` | Model for read-only PR review context scouting | +| `pr_review_max_context_tokens` | Legacy absolute PR review input token cap (0 = none) | +| `pr_review_context_budget_percent` | Review context budget as % of each reviewer's safe input capacity (10–100, steps of 10) | | `ultrafix_rating_goal` | Target quality rating for ultrafix cycles | | `ultrafix_max_cycles` | Maximum number of ultrafix cycles | | `ultrafix_pause_seconds` | Pause duration between ultrafix cycles | +`propr setting update` also accepts `pr-label`, `ai-primary-tag`, `primary-processing-labels`, and `followup-keywords` (comma-separated for the list keys). + ## Scripting Most commands accept `--json` for programmatic use: diff --git a/docs/docs/features/repository-knowledge.md b/docs/docs/features/repository-knowledge.md index a3e611f4d..99ec3c480 100644 --- a/docs/docs/features/repository-knowledge.md +++ b/docs/docs/features/repository-knowledge.md @@ -6,7 +6,7 @@ sidebar_position: 9 Repository knowledge helps ProPR plan and run with better context. Not every task needs it, but it becomes important once you use ProPR across larger or less familiar codebases. -The Repositories page in the Web UI is the home for this: each repository entry has a status indicator and reindex control, plus a workspace with four tabs — **Chat**, **Improve**, **Browse**, and **To-Dos**. +The Repositories page in the Web UI is the home for this: each repository entry has an indexing status indicator, and selecting it opens a workspace with **Chat**, **Improve**, **Browse**, and **To-Dos** tabs, plus **Settings** (where **Reindex** lives) and, when visual previews are enabled, **Media**. {/* SCREENSHOT PLACEHOLDER (P2 — interim: the site's ui-repositories.png): Capture the Repositories page with one indexed repository selected and its workspace open on the Browse tab, showing the tab row (Chat / Improve / Browse / To-Dos), the indexing status indicator, and the reindex button. Index the repository first so the status reads "Indexed". */} @@ -16,7 +16,7 @@ ProPR indexes monitored repositories and maintains file and repository summaries Summarization runs through a configurable agent and model, with an optional **fallback model** and quota-aware retry: when the primary model hits a provider quota, ProPR records a cooldown and switches to the fallback so indexing keeps progressing instead of failing. -A background indexing worker scans for repositories to index (every 5 minutes by default, `INDEXING_SCAN_INTERVAL_MS`) and refreshes existing indexes periodically (daily by default, `INDEXING_REINDEX_INTERVAL_MS`). You can also trigger reindexing manually with the reindex button on the repository entry, or with `propr repo index` from the CLI. +A background indexing worker scans for repositories to index (every 5 minutes by default, `INDEXING_SCAN_INTERVAL_MS`) and refreshes existing indexes periodically (daily by default, `INDEXING_REINDEX_INTERVAL_MS`). You can also trigger reindexing manually with **Reindex** in the repository's **Settings** tab, or with `propr repo index` from the CLI. Summaries are useful when: @@ -77,6 +77,6 @@ In those cases, reindex the repository, improve todos, add clearer workflow guid ## Reindexing And Recovery -If repository knowledge looks stale, use the reindex button on the repository entry (or `propr repo index`). Reindex before high-stakes runs after major refactors, dependency changes, directory moves, or repository renames. For routine follow-up on a small PR, the PR diff and comments may be enough. +If repository knowledge looks stale, use **Reindex** in the repository's **Settings** tab (or `propr repo index`). Reindex before high-stakes runs after major refactors, dependency changes, directory moves, or repository renames. For routine follow-up on a small PR, the PR diff and comments may be enough. Low-level indexing recovery details live in the operations docs; see [Maintenance And Troubleshooting](../operations/maintenance.md). diff --git a/docs/docs/features/self-hosting.md b/docs/docs/features/self-hosting.md index ca07ae5e1..78040f611 100644 --- a/docs/docs/features/self-hosting.md +++ b/docs/docs/features/self-hosting.md @@ -21,7 +21,7 @@ You supply the GitHub App credentials and agent credentials. ProPR does not requ The recommended setup is the published image set, orchestrated either by the ProPR CLI control plane or by one `docker run` of the launcher container. Both pull a pinned image set and start the service containers — Redis, daemon, worker, analysis and indexing workers, API, and Web UI — as siblings on the host Docker daemon, with your `.env`, data, logs, and repos directories mounted in. The image list and orchestration details live in [Production Deployment](../operations/deployment.md#published-images). -Local directory layout next to your `.env`: the GitHub App `.pem` (own-App mode only), plus `data/` (SQLite database), `logs/`, and `repos/` (clones and worktrees). This works for both local workstation setup and remote server deployment. See [Setup](../tutorials/setup.md) for the full flow, including the required GitHub App permissions (Contents R/W, Issues R/W, Pull Requests R/W, Metadata R, Actions R optional). +Local directory layout next to your `.env`: the GitHub App `.pem` (own-App mode only), plus `data/` (SQLite database), `logs/`, and `repos/`. Repository clones and per-task worktrees live under `/tmp/git-processor` on the host by default (`GIT_CLONES_BASE_PATH`, `GIT_WORKTREES_BASE_PATH`). This works for both local workstation setup and remote server deployment. See [Setup](../tutorials/setup.md) for the full flow, including the required GitHub App permissions (Contents R/W, Issues R/W, Pull Requests R/W, Metadata R, Actions R optional). ## Local Or Server diff --git a/docs/docs/features/synthetic-pools.md b/docs/docs/features/synthetic-pools.md index c0284b776..8f218ff91 100644 --- a/docs/docs/features/synthetic-pools.md +++ b/docs/docs/features/synthetic-pools.md @@ -52,7 +52,7 @@ Every later failover applies the same context requirement. A smaller-context fal ## Usage data and degraded pools -A capped member requires fresh Agent Tank data whose name exactly matches the direct-agent alias. Missing, refreshing, stale, provider-wide-only, or differently named data makes that capped member ineligible. The default freshness window is five minutes and can be changed with `SYNTHETIC_USAGE_FRESHNESS_MS`. +A capped member requires fresh Agent Tank data whose name exactly matches the direct-agent alias. Missing, refreshing, stale, provider-wide-only, or differently named data makes that capped member ineligible. The default freshness window is five minutes and can be changed with `SYNTHETIC_USAGE_FRESHNESS_MS`. In bundled Agent Tank mode, ProPR inspects only the first enabled account of each provider, so a capped member backed by a second account of the same provider (for example `codex-account-b`) has no alias-specific data and stays ineligible; use [external mode](../operations/agent-tank.md#external-mode) when every capped account must be measured, or leave that member uncapped. Uncapped pools do not require Agent Tank. If no member of a synthetic model is currently eligible, the pool reports **Degraded**. This does not mark its unrelated direct agents unhealthy; direct-agent health remains independent. @@ -77,7 +77,7 @@ propr agent pool delete balanced-pool --json `pool list --json` emits `{ "synthetic_agents": [...] }`. That file can be passed unchanged to `pool apply`; `apply` also accepts the array itself. Full-document replacement keeps nested multi-model configuration unambiguous and makes review, backup, and automation straightforward. Backend validation messages, including nested field paths, are printed without being rewritten. -An abbreviated two-tier document looks like this (IDs must be UUIDs): +An abbreviated two-tier document looks like this (synthetic agent and member IDs must be UUIDs; model IDs use lowercase letters, numbers and hyphens): ```json { diff --git a/docs/docs/features/usage-tips.md b/docs/docs/features/usage-tips.md index 4c630f831..ba291f033 100644 --- a/docs/docs/features/usage-tips.md +++ b/docs/docs/features/usage-tips.md @@ -4,13 +4,13 @@ A compact strip beneath historical dashboard statistics links to documented ProP ## Goals and launch strategies -Goals support two launch strategies: **Agent implements directly** opens a draft PR and commits changes at checkpoints; **Agent orchestrates through ProPR** lets the agent decompose work, create issues, and start and monitor their implementation. Use Goals for an ongoing objective and Planner Studio when you want to inspect and refine a plan before running it. +Goals support two launch strategies: **Direct** (the agent implements directly) opens a draft PR and commits changes at checkpoints; **Orchestrate through ProPR** lets the agent decompose work, create issues, and start and monitor their implementation. Use Goals for an ongoing objective and Planner Studio when you want to inspect and refine a plan before running it. ## Temporary dismissal Dismissals belong to your user account. Dismissing a tip hides it immediately and starts a cooling-off period. At the default 45 days, successive deliberate dismissals cool down for **45, 180, 720, and 2,880 days**. Further growth is capped at **3,650 days**. Expiry retains the lifetime dismissal count. A tip becomes eligible exactly at the cooldown boundary, but only appears if it remains relevant in the current selection. New relevance never overrides an active cooldown. -Settings → Automation exposes **Usage tips** (enabled by default) and **Dismissal cooldown days** (an integer from 1 to 365, default 45). Changing the base period recalculates existing cooldowns from each stored dismissal timestamp and lifetime count. Disabling tips hides the strip and stops daily selection. +Settings → Automation → **Usage tips** exposes **Show usage tips** (enabled by default) and **Dismissal cooldown days** (an integer from 1 to 365, default 45). Changing the base period recalculates existing cooldowns from each stored dismissal timestamp and lifetime count. Disabling tips hides the strip and stops daily selection. The CLI exposes the same settings: diff --git a/docs/docs/features/visual-previews.md b/docs/docs/features/visual-previews.md index b4760f2b6..4661463c8 100644 --- a/docs/docs/features/visual-previews.md +++ b/docs/docs/features/visual-previews.md @@ -162,7 +162,7 @@ for quota recovery, offline behavior, log handling, and release validation. ## View previews and recover private images -Task and goal details show published previews beside the work that produced them. Select an image to open the lightbox; double-click to zoom, use arrow keys to move between images and Escape to close it. Videos use their playback controls. +Task and goal details show published previews beside the work that produced them. Select an image to open the lightbox; double-click to zoom, use arrow keys to move between images and Escape to close it. Videos use their playback controls. [MCP](./mcp.md) clients can list a task's or pull request's published previews with `list_visual_previews` and fetch a downscaled image with `get_visual_preview`; videos are metadata only there and open on GitHub. ![Task detail showing published visual evidence in the full-width preview gallery](/img/screenshots/0.9.0/previews.png) diff --git a/docs/docs/features/voice-briefings.md b/docs/docs/features/voice-briefings.md index ed154b917..0611a0d79 100644 --- a/docs/docs/features/voice-briefings.md +++ b/docs/docs/features/voice-briefings.md @@ -79,7 +79,7 @@ A leading or trailing `please` is accepted. Follow-up text is limited to 1,000 c ### Confirmation is mandatory for mutations -`stop` and `follow up` never mutate state from the initial transcript. ProPR shows and speaks a specific confirmation prompt, and the user must select **Confirm action** or make a separate listening request and say `confirm`. Selecting **Cancel**, saying `cancel` or `never mind`, closing the panel, or sending another command does not execute the pending mutation. `open`, briefing, and repeat commands do not mutate server state and do not require confirmation. +`stop` and `follow up` never mutate state from the initial transcript. ProPR shows and speaks a specific confirmation prompt, and the user must select **Confirm** or make a separate listening request and say `confirm`. Selecting **Cancel**, saying `cancel` or `never mind`, closing the panel, or sending another command does not execute the pending mutation. `open`, briefing, and repeat commands do not mutate server state and do not require confirmation. The grammar is intentionally closed. Voice Briefings do **not** execute arbitrary shell commands, URLs, API requests, or free-form browser navigation. diff --git a/docs/docs/operations/agent-tank.md b/docs/docs/operations/agent-tank.md index 1a8b1d979..68276b1f1 100644 --- a/docs/docs/operations/agent-tank.md +++ b/docs/docs/operations/agent-tank.md @@ -112,7 +112,7 @@ This whole section is why bundled mode exists — none of it applies there. There are three ways to set it. All write the same backend setting. -**Detection banner (easiest).** While tracking is off, the dashboard and LLM Log page show a dismissible banner offering to turn it on in one click. If a daemon is already answering at `http://host.docker.internal:3456` the banner offers `external` pointed at it; otherwise it offers `bundled`. +**Detection banner (easiest).** While tracking is off, the dashboard shows a dismissible banner offering to turn it on in one click. If a daemon is already answering at `http://host.docker.internal:3456` the banner offers `external` pointed at it; otherwise it offers `bundled`, as long as at least one enabled Claude, Codex, or Antigravity agent has a credential directory to inspect. **Settings → LLM Usage Tracking.** Pick one of the three modes. The **Daemon URL** field only appears for `external`, because an external URL means nothing in the other two. The section shows a live status indicator so you can confirm the mode works before relying on it. diff --git a/docs/docs/operations/configuration-reference.md b/docs/docs/operations/configuration-reference.md index 022a4116f..125551ac6 100644 --- a/docs/docs/operations/configuration-reference.md +++ b/docs/docs/operations/configuration-reference.md @@ -13,14 +13,15 @@ The backend authenticates to GitHub in one of three modes — `demo`, `relay`, o | Variable | Default (shipped / code) | What it does | Required when | |---|---|---|---| -| `GH_AUTH_MODE` | Unset (mode is inferred) | Forces the auth mode: `app`, `relay`, or `demo`. Relay is inferred automatically when `PROPR_GH_RELAY_URL` + `PROPR_GH_RELAY_TOKEN` are set. | Rarely — only to override inference. | +| `GH_AUTH_MODE` | Unset (mode is inferred) | Forces the auth mode: `app`, `relay`, or `demo`. Relay is inferred automatically when `PROPR_GH_RELAY_TOKEN` is set (the relay URL defaults to the hosted relay). | Rarely — only to override inference. | | `PROPR_GH_RELAY_URL` | Hosted relay `https://webhook.propr.dev/v1` when unset | Token relay URL, including the version prefix (`https://`; `http` only for localhost). | Self-hosted relay only. | | `PROPR_GH_RELAY_TOKEN` | Unset | Durable relay credential issued for your install. `propr relay enroll` writes it. | Relay mode. | | `GH_INSTALLATION_ID` | Unset | Which GitHub App installation ProPR acts on. | Relay and app modes. | | `GH_APP_ID` | Unset | Your own GitHub App's numeric id. | App mode (own GitHub App). | | `GH_PRIVATE_KEY_PATH` | Unset | Path to your App's private key (`.pem`). | App mode. | | `HOST_GH_PRIVATE_KEY` | Unset | Absolute host path to the `.pem`. The CLI/launcher bind-mounts it read-only into the app containers and overrides `GH_PRIVATE_KEY_PATH`, so the key can live anywhere on the host. No `~`. | App mode via the `propr` CLI or launcher. | -| `GH_OAUTH_CLIENT_ID` / `GH_OAUTH_CLIENT_SECRET` | Placeholders | GitHub OAuth App credentials for Web UI login. | Always, for UI login. | +| `PROPR_WEB_AUTH_MODE` | Inferred | Browser login mode: `connect` (ProPR Connect and the shared ProPR GitHub App), `github` (your own OAuth App), or `disabled`. Unset, it is `connect` for a relay-enrolled stack with the tunnel enabled, then `github` when OAuth client credentials are set, then `connect` for a stack enrolled with the hosted relay whose callback is on localhost, and otherwise `disabled`. `propr setup` and `propr tunnel setup` write `connect`. | Override only. | +| `GH_OAUTH_CLIENT_ID` / `GH_OAUTH_CLIENT_SECRET` | Unset | GitHub OAuth App credentials for Web UI login in `github` mode. Relay-enrolled installs log in through Connect and do not need them. | `github` login mode only. | | `GH_OAUTH_CALLBACK_URL` | Derived: `/api/auth/github/callback` | OAuth callback served by the API. Leave commented so tunnel-mode derivation wins; an active localhost value is used as-is even in tunnel mode. Register the URL — derived or explicit — in your GitHub OAuth App. | Override only. | | `GITHUB_VISUAL_PREVIEW_TOKEN` | Unset | Advanced override for the OAuth App token (`gho_`), classic PAT, or fine-grained PAT used only to upload visual-preview attachments. Administrators can normally paste a PAT in Settings instead, and `propr setup` imports a compatible `gh` CLI token when available. GitHub's uploader rejects GitHub App user (`ghu_`) and installation (`ghs_`) tokens. | Optional override. | | `PROPR_CREDENTIAL_ENCRYPTION_KEY` | `SYSTEM_TASK_SECRET`, then `SESSION_SECRET` | Optional dedicated secret used to encrypt the persisted visual-preview OAuth grant. It must be identical in the API and worker containers and remain stable across restarts; changing it requires reconnecting the GitHub login. | Optional security isolation. | @@ -49,7 +50,10 @@ The backend authenticates to GitHub in one of three modes — `demo`, `relay`, o | `PROPR_AUTH_RATE_LIMIT_MAX` / `PROPR_AUTH_RATE_LIMIT_WINDOW_MS` | `30` / `900000` | Additional, tighter per-client quota for OAuth initiation and callback endpoints. | Optional tuning. | | `PROPR_WEBHOOK_RATE_LIMIT_MAX` / `PROPR_WEBHOOK_RATE_LIMIT_WINDOW_MS` | `300` / `60000` | Per-client quota for direct webhook requests, applied before body parsing and signature verification. | Optional tuning in direct-webhook mode. | | `PROPR_TRUSTED_PROXY_PEERS` | Unset; launcher-managed tunnel: reserved `self` mode | Comma-separated immediate proxy IPs, CIDRs, or `proxy-addr` names whose forwarded client IP and protocol are trusted. Unset ignores forwarding headers. The launcher injects `self` only for its managed sidecar sharing the API network namespace. Its broad `uniquelocal` name is accepted only when `API_PORT` is explicitly loopback-bound. | Reverse-proxy deployments; injected automatically for the managed tunnel. | +| `PROPR_DESKTOP_TOKEN_TTL_DAYS` | Unset (no expiry) | Lifetime of newly paired desktop instance tokens, 1–3650 days. See [Desktop Pairing](./desktop-pairing.md). | Optional. | +| `PROPR_DISCOVERY_RATE_LIMIT_MAX` / `PROPR_PAIRING_START_RATE_LIMIT_MAX` / `PROPR_PAIRING_POLL_RATE_LIMIT_MAX` | `60` per minute / `10` per 15 minutes / `180` per 15 minutes | Per-client quotas for desktop discovery, pairing start, and pairing polls. Matching `*_WINDOW_MS` variables set the windows. | Optional tuning. | | `LOG_LEVEL` | `info` | Log verbosity across services. | Optional. | +| `PROPR_API_TIMING_SAMPLE_RATE` | `0` (off) | Fraction of API requests (0–1) whose static route/stage names and durations are logged. Request URLs, parameters, headers, bodies, credentials and SQL are never logged. | Temporary latency diagnosis. | | `NODE_ENV` | `development` in the source template; `production` in stacks scaffolded by the packaged CLI | Packaged API, daemon, and worker containers require `production`. Source-development commands may use `development`. Existing files are preserved during upgrades; if an older generated stack still says `development`, review it and change it to `production` before running `propr start`. | Optional. | | `DB_FILENAME` | `./data/propr.sqlite` | Path to the SQLite database file (created if it doesn't exist). | Optional. | @@ -66,13 +70,13 @@ How ProPR receives GitHub events, plus what it watches for once they arrive. All | `POLLING_INTERVAL_MS` | `60000` | Poll period when pulling events from the GitHub API. | Polling mode only. | | `GH_WEBHOOK_SECRET` | Unset | Shared secret GitHub signs webhook deliveries with. | Direct webhook mode. | | `GITHUB_REPOS_TO_MONITOR` | Unset | Optional authoritative, comma-separated repository list when `CONFIG_REPO` is unset. When neither variable is set, the daemon uses repositories selected through setup or Settings and reloads that persisted list live. | Static environment-managed deployments only. | -| `CONFIG_REPO` | Example config repo URL | Legacy external config-repository switch; when set, processing labels and persisted repo config load dynamically. | Optional. | +| `CONFIG_REPO` | Unset | Legacy external config-repository switch; when set, processing labels and persisted repo config load dynamically. | Optional. | | `PRIMARY_PROCESSING_LABELS` | Shipped `AI,propr` / code falls back to `AI` | Issue labels that trigger processing. | Optional. | | `PR_LABEL` | `propr` | Label applied to PRs ProPR creates. | Optional. | -| `GITHUB_BOT_USERNAME` | Placeholder / code falls back to `propr-dev[bot]` | The bot identity, used to filter its own comments out of triggers. | Optional. | +| `GITHUB_BOT_USERNAME` | Shipped `propr.dev[bot]` / code auto-detects the App's `[bot]`, falling back to `propr-dev[bot]` | The bot identity, used to filter its own comments out of triggers. | Optional. | | `GITHUB_USER_WHITELIST` / `GITHUB_USER_BLACKLIST` | Empty | Comma-separated allow/deny lists for who can trigger processing. | Optional. | | `PROPR_ADMIN_USERS` | Empty | Comma-separated authenticated GitHub usernames that bootstrap instance administrators. Non-demo startup fails when neither this list nor a durable administrator exists. The list remains an independent, authoritative override while configured. **Username risk:** GitHub usernames can be renamed or recycled; store the bootstrap role from **Web UI → Access** to bind it to the numeric GitHub ID, then remove or carefully maintain the environment entry. | Initial setup, or optional break-glass access. | -| `PR_FOLLOWUP_TRIGGER_KEYWORDS` | `!propr` | Keywords in PR comments that trigger follow-up work. See [PR Follow-up](../features/pr-followup.md). | Optional. | +| `PR_FOLLOWUP_TRIGGER_KEYWORDS` | Shipped `!propr` / unset or empty: no keyword is required | Keywords in PR comments that trigger follow-up work on PRs without a processing label. With no keywords, every comment passes the keyword check. See [PR Follow-up](../features/pr-followup.md). | Optional. | | `CANCEL_CI_FOLLOWUP_WORKFLOWS` | Unset (nothing selected) | Fallback selection of the workflows the per-repository option *Cancel CI while follow-up implementation is in progress* may cancel, for instances configured outside the Web UI. Comma-separated, matched case-insensitively and exactly by workflow display name, file path, file name or numeric ID — never as a substring. Applies only to repositories whose own selection is empty; a repository selection always wins. With neither, nothing is cancelled. See [PR Follow-up](../features/pr-followup.md#cancelling-obsolete-checks-during-follow-up). | Optional; only with that option enabled. | | `LABEL_APPLIER_TIMELINE_MAX_PAGES` | `5` | With a whitelist set, polling resolves who applied the trigger label from the issue timeline (page 1 + the most recent N pages). Raise it if long-lived issues are skipped with "Could not determine label applier". | Optional. | @@ -86,7 +90,7 @@ Unified image selection, per-agent credential paths, and execution limits. Codin | `AGENT_CONTAINER_MEMORY_LIMIT` | `6g` | Hard memory and memory-plus-swap ceiling applied to every coding-agent container. Use a positive Docker memory value such as `8g`. | Optional tuning. | | `AGENT_CONTAINER_CPU_LIMIT` | Adaptive: `min(4, detected CPUs)` | Maximum CPUs available to each coding-agent container; fractional overrides such as `1.5` are accepted. Leave unset to stay within the worker host's detected capacity. | Optional tuning. | | `AGENT_CONTAINER_PIDS_LIMIT` | `512` | Maximum processes/threads available to each coding-agent container. | Optional tuning. | -| `PROPR_MANAGED_CREDENTIALS_DIR` | Native/Compose: `~/.propr/agent-credentials`; launcher: `PROPR_DATA_DIR/agent-credentials` | Host-visible root for isolated accounts created through direct Web login. The default is derived automatically; a launcher/CLI override must be an absolute Docker-host path. | Optional advanced override. | +| `PROPR_MANAGED_CREDENTIALS_DIR` | CLI, native and Compose: `~/.propr/agent-credentials`; launcher container: `PROPR_DATA_DIR/agent-credentials` | Host-visible root for isolated accounts created through direct Web login. The default is derived automatically; a launcher/CLI override must be an absolute Docker-host path. | Optional advanced override. | | `CLAUDE_CONFIG_PATH` | Empty | Absolute path to an existing `~/.claude` directory. `~` and `${HOME}` are **not** expanded in `.env` files or Docker bind mounts. Direct-login agents do not need this setting. | Reusing an existing Claude account. | | `CLAUDE_MAX_TURNS` | Shipped `10` / code falls back to `1000` if unset | Maximum agent turns per Claude run. | Optional. | | `CLAUDE_TIMEOUT_MS` | `86400000` (24 hours) | Claude task run timeout. | Optional. | @@ -94,6 +98,7 @@ Unified image selection, per-agent credential paths, and execution limits. Codin | `CODEX_STREAM_TRANSPORT` | `websocket` | Codex response transport. `websocket` avoids long-lived HTTP response deadlines, `sse` supports environments that cannot carry WebSockets, and `inherit` leaves the mounted Codex provider configuration unchanged. | Optional; use `inherit` with a custom provider. | | `CODEX_STREAM_IDLE_TIMEOUT_MS` | `1800000` (30 minutes) | Maximum quiet period on a Codex response stream before reconnecting. This is separate from the whole-task `CODEX_TIMEOUT_MS`. | Optional tuning. | | `CODEX_STREAM_MAX_RETRIES` | `5` | Number of Codex response-stream reconnect attempts. Zero disables retries. | Optional tuning. | +| `ANALYSIS_MODEL_FAST` / `PLANNER_CONTEXT_MODEL` / `PLANNER_GENERATION_MODEL` | Unset | Initial values the settings API reports for the fast-analysis and planner models while **Settings → Models** has no saved value; `ANALYSIS_MODEL_FAST` is also the PR-review fast-analysis fallback. A saved setting wins. Prefer choosing models in Settings. | Optional. | | `CONTEXT_ANALYSIS_TIMEOUT_MS` | `3600000` (60 minutes) | Timeout for planner keyword extraction and semantic relevance scoring calls. | Optional. | | `PROPR_PLAN_GENERATION_MODE` | `file` | `file`: the planning agent writes one JSON file per issue in a scratch workspace and runs the plan validator until it passes; ProPR re-validates before saving. `response`: the plan is parsed from the agent's reply. If the file workspace or agent cannot be started at all, ProPR falls back to `response` for that run; an invalid plan fails instead. | Optional. | | `PROPR_PLAN_WORKSPACE_ROOT` | `/tmp/git-processor/plan-workspaces` | Scratch workspaces for plan agents. Must be the same path for the API and the Docker daemon, like the worktree root. | Custom worktree layouts only. | @@ -119,6 +124,9 @@ Queue and worker behavior; see [Worker Runtime](../architecture/worker-runtime.m | `GITHUB_ISSUE_QUEUE_NAME` | `github-issue-processor` | Name of the issue-processing queue. | Optional. | | `WORKER_CONCURRENCY` | Shipped `2` / code falls back to `5` if unset | Jobs a worker processes in parallel. | Optional. | | `COMMENT_BATCH_DELAY_MS` | `3000` | Delay for batching GitHub comment updates. | Optional. | +| `TASK_STATE_RECONCILIATION_INTERVAL_MS` / `TASK_STATE_RECONCILIATION_STALE_MS` | `60000` / `900000` | How often the worker reconciles persisted task state with live queue jobs and containers, and how long after its last state update an unfinished task becomes eligible for that check. | Optional tuning. | +| `TASK_STATE_RECONCILIATION_ORPHAN_GRACE_MS` / `TASK_STATE_RECONCILIATION_BATCH_SIZE` / `TASK_STATE_RECONCILIATION_TIME_BUDGET_MS` | `60000` / `100` / `30000` | Grace window across which a missing job or container must be observed repeatedly before a task is treated as orphaned, tasks checked per pass, and the time budget per pass. | Optional tuning. | +| `PR_TASK_TITLE_GENERATION_TIMEOUT_MS` | `30000` | Timeout for the lightweight agent call that titles PR comment tasks, including container startup. | Optional tuning. | | `SUMMARIZATION_FALLBACK_PROMOTE_THRESHOLD` | `3` | Promotes the summarization fallback to primary after this many primary quota failures for the same agent/model. | Optional. | | `SUMMARIZATION_QUOTA_COOLDOWN_MS` | `3600000` (1 hour) | Pauses normal summarization jobs for a repository/branch after both primary and fallback paths fail. | Optional. | | `SYSTEM_TASK_SECRET` | Empty | Signs system task requests (for example revert operations). Generate with `openssl rand -hex 32`. | System tasks (reverts). | @@ -157,5 +165,7 @@ These variables are read from code but are not in `.env.example` — Agent Tank | Variable | Default (shipped / code) | What it does | Required when | |---|---|---|---| | `ENABLE_GITHUB_WEBHOOKS` | Deprecated | No longer selects the intake mode; use `GITHUB_EVENT_INTAKE_MODE` instead. Present only so existing `.env` files are recognized — a deprecation warning is logged when it is set. | Never — remove it. | +| `MCP_ENABLED` and other `MCP_*` variables | Shipped `MCP_ENABLED=false` / unset: managed in **Settings → Integrations → MCP Server** | `true` selects environment-managed MCP configuration; `false` prevents enabling MCP from the UI, so remove or comment out the shipped line to manage MCP in Settings. See [MCP](../features/mcp.md). | Environment-managed MCP, or keeping MCP off. | +| `PROPR_DOCS_DIR` | Bundled docs in the app image | Documentation root served to agents by the MCP docs tools. Override only to mount a different docs checkout; a version mismatch with the running API is reported as a warning. | Override only. | | `STAGING_ENV_FILE` | Placeholder | Path to a staging `.env` that provides base configuration for PR preview environments. Consumed by `docker-compose.yml` and `scripts/deploy-pr.sh`; the PR Preview workflow maps repository variables onto it. | Contributor PR preview deploys only. | | `STAGING_DB_PATH` | Placeholder | Optional staging database file for seeding PR preview environments. | Contributor PR preview deploys only. | diff --git a/docs/docs/operations/connect-dashboard.md b/docs/docs/operations/connect-dashboard.md index 413dbe694..77eb454c5 100644 --- a/docs/docs/operations/connect-dashboard.md +++ b/docs/docs/operations/connect-dashboard.md @@ -32,7 +32,7 @@ Plus installations can provision a managed hosted-UI tunnel: Connect creates the When you suspect the hosted side rather than your stack: - `https://webhook.propr.dev/health` returns `{ "ok": true }` when the relay worker is up. -- `propr status` (and `propr remote-status`) report your stack's routing connection and, when enabled, tunnel reachability. +- `propr remote-status` reports your stack's routing connection; `propr status` reports tunnel reachability when a tunnel is configured. - `propr tunnel verify` checks the tunnel end to end. - The Deliveries page shows whether GitHub events are arriving and being acknowledged — a growing failed-deliveries count with a healthy stack points at connectivity between the two. diff --git a/docs/docs/operations/deployment.md b/docs/docs/operations/deployment.md index 523627ce9..208dd6975 100644 --- a/docs/docs/operations/deployment.md +++ b/docs/docs/operations/deployment.md @@ -42,7 +42,7 @@ chmod 600 your-app-private-key.pem | `your-app-private-key.pem` | GitHub App private key — **only in own GitHub App mode**; relay mode (`GH_AUTH_MODE=relay`) stores no key file here | | `data/` | SQLite database (`propr.sqlite` plus `-wal`/`-shm` files) | | `logs/` | Log directory mounted into the service containers at `/usr/src/app/logs` | -| `repos/` | Git working area: `clones/` (cached repository clones) and `worktrees/` (per-task worktrees) | +| `repos/` | Mounted into the worker at `/usr/src/app/repos`. Cached clones and per-task worktrees live under `/tmp/git-processor` on the host by default (`GIT_CLONES_BASE_PATH`, `GIT_WORKTREES_BASE_PATH`) | Redis data lives outside this directory, in the Docker volume `propr-redis-data`. @@ -63,24 +63,16 @@ Images are published to Docker Hub under the `propr/` namespace. Docker Hub is t ## Environment -Use `.env` for server-specific wiring. The GitHub App private-key variable -depends on whether you start the stack with the **CLI** or the **launcher**: - -| Variable | When to use | Value | -|---|---|---| -| `HOST_GH_PRIVATE_KEY` | **CLI** (`propr start`) | Absolute **host** path to the `.pem` file — the CLI bind-mounts it into the container | -| `GH_PRIVATE_KEY_PATH` | **Launcher** (`docker run propr/launcher`) | Path **inside the launcher container** (typically `/app/config/...` via a `-v` mount) | - -Do not mix them — the CLI cannot resolve a container-internal path, and the -launcher cannot resolve a host path it has not mounted itself. +Use `.env` for server-specific wiring. Point `HOST_GH_PRIVATE_KEY` at the GitHub +App private key (`.pem`) using an absolute **host** path. Both the CLI (`propr start`) +and the launcher bind-mount that file read-only into the app containers at the same +path and set `GH_PRIVATE_KEY_PATH` for them, so you don't set `GH_PRIVATE_KEY_PATH` +yourself or mount the key into the launcher. ```bash GH_APP_ID=your-github-app-id GH_INSTALLATION_ID=your-installation-id - -# Pick ONE of the following, depending on your start method: -HOST_GH_PRIVATE_KEY=/srv/propr/your-app-private-key.pem # CLI -# GH_PRIVATE_KEY_PATH=/app/config/your-app-private-key.pem # Launcher +HOST_GH_PRIVATE_KEY=/srv/propr/your-app-private-key.pem FRONTEND_URL=https://propr.example.com GH_OAUTH_CLIENT_ID=your_github_oauth_client_id @@ -88,14 +80,12 @@ GH_OAUTH_CLIENT_SECRET=your_github_oauth_client_secret GH_OAUTH_CALLBACK_URL=https://propr.example.com/api/auth/github/callback SESSION_SECRET=generate-a-strong-secret-here -DB_FILENAME=/app/data/propr.sqlite -GIT_CLONES_BASE_PATH=/app/repos/clones -GIT_WORKTREES_BASE_PATH=/app/repos/worktrees +DB_FILENAME=./data/propr.sqlite ``` All `HOST_*_DIR` values and launcher path variables must be absolute host paths. `.env` parsing does not expand `~` or `$HOME`. -Manage repositories, labels, branches, and agents in the Web UI after startup. Direct-login agent accounts need no `HOST_*` path: native installs store them below `~/.propr/agent-credentials`, while the launcher derives an isolated root below `PROPR_DATA_DIR`. +Manage repositories, labels, branches, and agents in the Web UI after startup. Direct-login agent accounts need no `HOST_*` path: CLI-started, native and Compose installs store them below `~/.propr/agent-credentials`, while the launcher container derives an isolated root below `PROPR_DATA_DIR`. For Antigravity agents, install the CLI on the host and authenticate before launching the stack: @@ -202,7 +192,6 @@ container provides the same orchestration: docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$PWD/.env:/app/.env:ro" \ - -v "$PWD/your-app-private-key.pem:/app/config/your-app-private-key.pem:ro" \ -e PROPR_ENV_FILE="$PWD/.env" \ -e PROPR_DATA_DIR="$PWD/data" \ -e PROPR_LOGS_DIR="$PWD/logs" \ @@ -213,12 +202,9 @@ docker run --rm \ propr/launcher:latest ``` -The private-key mount (`-v ...your-app-private-key.pem...`) is needed **only in -own GitHub App mode**, where it pairs with `GH_PRIVATE_KEY_PATH=/app/config/...` -in `.env`. In relay mode (`GH_AUTH_MODE=relay`) there is no key file — omit that -line. Do not also set `HOST_GH_PRIVATE_KEY` here: that variable is for the CLI -start path, and the two key variables must not be mixed (see -[Environment](#environment) above). +In own GitHub App mode, set `HOST_GH_PRIVATE_KEY` in `.env` to the key's absolute +host path; the launcher mounts it into the app containers (see +[Environment](#environment) above). Relay mode (`GH_AUTH_MODE=relay`) needs no key. The path variables are passed as environment values; mounting them would not work because the launcher spawns sibling containers through the host Docker daemon, and every `-v` value it passes must resolve on the host. diff --git a/docs/docs/operations/desktop-application.md b/docs/docs/operations/desktop-application.md index 557916fed..324f0614f 100644 --- a/docs/docs/operations/desktop-application.md +++ b/docs/docs/operations/desktop-application.md @@ -13,7 +13,7 @@ local ProPR stack for you. The desktop app does not change the browser Web UI, C | Platform | Packages | Connect to an instance | Guided local setup | | --- | --- | --- | --- | | Linux x64 | DEB, RPM, ZIP | Yes | Yes | -| Linux arm64 | DEB, RPM, ZIP | Yes | No: the ProPR runtime images are published for `amd64` only | +| Linux arm64 | DEB, RPM, ZIP | Yes | No: the `propr/agent` image is published for `amd64` only | | macOS Intel | DMG, ZIP | Yes | No | | macOS Apple Silicon | DMG, ZIP | Yes | No | | Windows | Not available yet | | | @@ -125,7 +125,7 @@ stack's containers with the packaged versions and keeps its database, credential ## Version and diagnostics **About ProPR** shows the app version and a **Copy Version Details** action. **Connection Diagnostics** shows the -connected server and runtime version separately. Updating the desktop app does not upgrade a remote instance. +desktop app version and the connected instance's version separately. Updating the desktop app does not upgrade a remote instance. Installation-level **Settings** belong to the connected server. Connection management and diagnostics belong to the app. @@ -133,10 +133,13 @@ Installation-level **Settings** belong to the connected server. Connection manag | Menu | Actions and shortcuts | | --- | --- | -| ProPR | About ProPR, Settings… (`Cmd+,`), Services, Hide, Quit ProPR | -| File | New Plan (`Cmd+N`), Switch / Manage Instances… (`Cmd+Shift+I`), Close Window | -| Go | Back (`Cmd+[`), Forward (`Cmd+]`), Dashboard (`Cmd+1`), Inbox (`Cmd+2`), Plans (`Cmd+3`), Goals (`Cmd+4`), Tasks (`Cmd+5`), Repositories (`Cmd+6`), LLM Log (`Cmd+7`) | -| Edit / View / Window | Native editing, zoom/fullscreen, minimize, zoom window, bring all to front | +| ProPR | About ProPR, Settings… (`Cmd+,`), Services and Hide (macOS only), Quit ProPR (`Cmd+Q`) | +| File | New Plan (`Cmd+N`), New Task…, Connect Instance…, Switch Account / Instance… (`Cmd+Shift+I`), Close Window | +| Edit | Native editing | +| View | Toggle Sidebar, zoom, full screen | +| Navigate | Back (`Cmd+[`), Forward (`Cmd+]`), Search / Go To… (`Cmd+K`), Dashboard, Inbox, Plans, Goals, Tasks, Repositories | +| Window | Minimize; on macOS also zoom window and bring all to front | +| Help | ProPR Website, Documentation, Connection Help, Connection Diagnostics…, Report a Problem… | On Linux, use `Ctrl` in place of `Cmd`. The Linux tray icon and the macOS menu-bar item show task and plan counts and offer New Plan, Tasks, Plans, Inbox, instance switching, notification settings, and pausing or resuming native @@ -166,7 +169,7 @@ Saved instances and accounts are kept across updates. ## Troubleshooting -- **No local setup option:** guided setup is available on Linux x64 only. +- **No local setup option:** guided setup is offered on Linux only, and supported on x64. - **Docker absent, down or permission denied:** install and start Docker, add your user to the `docker` group, then retry. - **Authentication terminal unavailable:** install one of the supported terminal emulators and retry. - **Secure storage unavailable:** start an unlocked Secret Service keyring session. Pairing never falls back to a diff --git a/docs/docs/operations/desktop-pairing.md b/docs/docs/operations/desktop-pairing.md index dcf954a46..667717a5a 100644 --- a/docs/docs/operations/desktop-pairing.md +++ b/docs/docs/operations/desktop-pairing.md @@ -81,16 +81,30 @@ discovery and identity contract. `{"deviceSecret":"..."}`. The secret is in the JSON body, never a URL or header that an intermediary normally logs. A pending request returns `202` with `{"status":"pending","interval":5}`. -5. The first valid poll after approval returns `200` with - `{"status":"complete","token":"propr_it_...","tokenType":"Bearer","expiresAt":null}`. - The polling grant is consumed in the same transaction that creates the token; - subsequent polls return `409 PAIRING_ALREADY_CONSUMED`. If the success response - is lost, begin a new pairing rather than retrying for the credential. +5. The first valid poll after approval returns `200` with a provisional + credential: + `{"status":"provisional","token":"propr_it_...","tokenType":"Bearer","activationTicket":"...","activationExpiresAt":"...",...}`, + plus the pairing's `instanceId`, `origin`, `scope`, and + `credentialGeneration` binding. A provisional token authenticates nothing. + Repeating the poll before activation returns the same token and ticket, so a + lost response can be recovered. +6. After storing the token securely, the trusted process sends + `POST /api/desktop/pairings/{pairingId}/activate` with `deviceSecret`, + `activationTicket`, and the same binding fields. A `200` response + `{"status":"active","receipt":"...","activatedAt":"...","expiresAt":null}` + makes the token usable and consumes the pairing; repeating the same + activation returns the same receipt. Activation must happen within two + minutes of the first provisional poll and before the pairing expires. To + abandon a provisioned credential instead, send the same body to + `POST /api/desktop/pairings/{pairingId}/cancel`. Once a pairing is consumed, + further polls return `409 PAIRING_ALREADY_CONSUMED` (or + `410 PAIRING_CANCELLED` after a cancel). Pairings expire after ten minutes. An unknown ID or wrong secret returns the same `404 PAIRING_NOT_FOUND`; an expired request returns `410 PAIRING_EXPIRED`. -Start and poll routes have separate IP quotas. Clients must honor HTTP `429` and -`Retry-After` and must stop at `expiresAt`. +Start and poll routes have separate IP quotas; activate and cancel share the +poll quota. Clients must honor HTTP `429` and `Retry-After` and must stop at +`expiresAt`. ## Using and storing the token @@ -126,7 +140,7 @@ cleaned hourly after a short retention period used for stable client errors. ## Token management Both routes require any accepted authentication method and operate only on the -authenticated user's tokens: +authenticated user's activated tokens: - `GET /api/desktop/tokens` returns `{ "tokens": [...] }` with `id`, `name`, `tokenHint`, `createdAt`, `lastUsedAt`, `expiresAt`, and `revokedAt`. It never @@ -135,6 +149,11 @@ authenticated user's tokens: owned token. Unknown, already-revoked, and other users' IDs all return `404 TOKEN_NOT_FOUND`. +A desktop client can also revoke its own credential with +`DELETE /api/desktop/tokens/current`, presenting the token as the bearer +credential and its credential generation in the +`X-ProPR-Desktop-Revocation-Binding` header; it returns `204` on success. + Pairing start, approval, token issuance, and revocation write audit rows and structured logs containing IDs and the display name only. Device secrets, instance tokens, token hashes, and GitHub tokens are excluded. diff --git a/docs/docs/operations/github-auth.md b/docs/docs/operations/github-auth.md index f37b3a445..266ff317e 100644 --- a/docs/docs/operations/github-auth.md +++ b/docs/docs/operations/github-auth.md @@ -4,7 +4,8 @@ The ProPR backend (daemon, workers, API) acts on GitHub as a **GitHub App** — it reads labeled issues, pushes branches, and opens pull requests as the app's bot identity. There are three ways to configure how the backend obtains a GitHub **installation access token**. The mode is inferred from your environment -(precedence: demo → relay → app), or set explicitly with `GH_AUTH_MODE`. +(precedence: demo → relay → app), or set explicitly with `GH_AUTH_MODE`, which +overrides inference except for `PROPR_DEMO_MODE=true`. For the hosted bridge that provides relay auth, GitHub event routing, failed delivery recovery, and optional hosted UI tunnels, see @@ -35,7 +36,7 @@ private key. Instead the stack fetches short-lived installation tokens from a vendor-run **relay**, authenticated by a durable per-installation credential. ```bash -GH_AUTH_MODE=relay # optional but recommended; relay is also inferred from URL+token +GH_AUTH_MODE=relay # optional but recommended; relay is also inferred from the token PROPR_GH_RELAY_URL=https://webhook.propr.dev/v1 # optional; defaults to the hosted relay. https required (http only for localhost), include version prefix PROPR_GH_RELAY_TOKEN=your_relay_token # durable credential issued for your installation GH_INSTALLATION_ID=987654 # optional; which installation diff --git a/docs/docs/operations/hosted-ui-tunnel.md b/docs/docs/operations/hosted-ui-tunnel.md index ae81fce1f..bf905cc15 100644 --- a/docs/docs/operations/hosted-ui-tunnel.md +++ b/docs/docs/operations/hosted-ui-tunnel.md @@ -58,7 +58,7 @@ ProPR Connect provisions the Cloudflare Tunnel and instance id for Plus installa propr tunnel setup --token --url https://t-abc123.propr.dev --start ``` -This writes the tunnel `.env` values for you (`PROPR_UI_TUNNEL_TOKEN`, `PROPR_INSTANCE_ID`, `PROPR_UI_PUBLIC_API_URL`, `API_PUBLIC_URL`, `FRONTEND_URL`, `GH_OAUTH_CALLBACK_URL`, `PROPR_WEB_AUTH_MODE=connect`), records the tunnel as enabled, and — with `--start` — starts a stopped stack or recreates a running one so the hosted URLs apply immediately. Prefer this command over hand-editing `.env`: it also overwrites stale localhost values left over from a previous local setup. +This writes the tunnel `.env` values for you (`PROPR_UI_TUNNEL_TOKEN`, `PROPR_UI_TUNNEL_ENABLED=true`, `PROPR_INSTANCE_ID`, `PROPR_UI_PUBLIC_API_URL`, `API_PUBLIC_URL`, `FRONTEND_URL`, `GH_OAUTH_CALLBACK_URL`, `PROPR_WEB_AUTH_MODE=connect`), records the tunnel as enabled, and — with `--start` — starts a stopped stack or recreates a running one so the hosted URLs apply immediately. Prefer this command over hand-editing `.env`: it also overwrites stale localhost values left over from a previous local setup. ### Manual `.env` fallback @@ -131,7 +131,7 @@ Desktop invokes an explicit stack root; the CLI never scans for installations: propr connect status --json --root /explicit/stack/root ``` -Stdout is exactly one schema-versioned JSON document. It reports only the canonical endpoint, public installation identity, configured/enabled/sidecar/API readiness, restart requirement, compatibility/version, and bounded reason codes. `configured` means that a valid canonical endpoint exists; it deliberately says nothing about whether any credential is present. Diagnostics go to stderr. It never reports token presence or values, GitHub/account/repository identity, host details, environment contents, or filesystem paths. Exit codes are stable: `0` ready, `2` known not ready, `3` incompatible discovery/API, `4` invalid configuration/root, `5` probe timeout, and `1` internal failure. +Stdout is exactly one schema-versioned JSON document. It reports only the canonical endpoint, public installation identity, configured/enabled/sidecar/API readiness, restart requirement, compatibility/version, and bounded reason codes. `configured` means that a valid canonical endpoint exists; it deliberately says nothing about whether any credential is present. Diagnostics go to stderr. It never reports token presence or values, GitHub/account/repository identity, host details, environment contents, or filesystem paths. Exit codes are stable: `0` when the document was produced for a ready, not-ready, or timed-out probe (read `status` to tell them apart), `2` for incompatible discovery/API, and `1` for invalid configuration/root or an internal failure. The public identity is generated randomly in the stack's durable `data/` boundary. It survives normal restart, image upgrade, and tunnel rotation. Replacing/reinitializing that durable stack data generates a new identity. A sidecar is not `apiReady` until the remote discovery response matches both the expected canonical origin and this identity; consequently, `propr tunnel on` without an API restart reports `restartRequired` instead of a false-ready endpoint. diff --git a/docs/docs/operations/maintenance.md b/docs/docs/operations/maintenance.md index 06537532c..205bfc8e9 100644 --- a/docs/docs/operations/maintenance.md +++ b/docs/docs/operations/maintenance.md @@ -95,7 +95,7 @@ docker logs -f propr-api Other locations: - The host `logs/` directory (`PROPR_LOGS_DIR`) is mounted into the service containers at `/usr/src/app/logs`. -- Agent session logs are written under `/tmp/claude-logs` (mounted into worker, analysis, and API containers), and are surfaced per task in the Web UI task detail view and through the `/api/execution/...` endpoints. +- Agent session logs are written under `/tmp/claude-logs` on the host (shared with the worker containers and the agent containers they start), and are surfaced per task in the Web UI task detail view and through the `/api/execution/...` endpoints. - Per-LLM-call records are stored in the SQLite `llm_logs` table and shown on the LLM Log page; see [Metrics](./metrics.md). - Set `LOG_LEVEL=debug` in `.env` for more verbose service logs. @@ -105,20 +105,20 @@ Back up: - The SQLite database (`data/propr.sqlite`, including `-wal`/`-shm` files) — the primary application state. Copy it while the stack is stopped, or use `sqlite3 propr.sqlite ".backup backup.sqlite"` for a consistent snapshot of a live database (WAL mode is enabled) - Production `.env` and the GitHub App private key (or the secret source that produces them) -- ProPR's managed agent credential root if you use direct login (`~/.propr/agent-credentials` for native/Compose installs or `PROPR_DATA_DIR/agent-credentials` for the launcher) +- ProPR's managed agent credential root if you use direct login (`~/.propr/agent-credentials` for CLI-started, native and Compose installs, or `PROPR_DATA_DIR/agent-credentials` for the launcher container) - The `propr-redis-data` Docker volume if you want queue state and sessions to survive a restore - Logs, if you need history -`repos/` is a working area: clones are re-created on demand and worktrees are per-task, so it needs no backup. Do not back up only `repos/` and `logs/` — they do not contain the application state. The runtime directory these paths live in is described in [Deployment → Runtime Directory Layout](./deployment.md#runtime-directory-layout). +Git clones and worktrees (under `/tmp/git-processor` by default) are a working area: clones are re-created on demand and worktrees are per-task, so they need no backup. Do not back up only `repos/` and `logs/` — they do not contain the application state. The runtime directory these paths live in is described in [Deployment → Runtime Directory Layout](./deployment.md#runtime-directory-layout). ## Repository And Worktree Cleanup -ProPR keeps Git state under `repos/`: +ProPR keeps Git state under `/tmp/git-processor` on the host. The launcher mounts that path at the same location in every service container, so agent containers can bind-mount worktrees by their host path: -- `repos/clones/` — cached clones, one per monitored repository (`GIT_CLONES_BASE_PATH`) -- `repos/worktrees/` — per-task worktrees (`GIT_WORKTREES_BASE_PATH`) +- `/tmp/git-processor/clones/` — cached clones, one per monitored repository (`GIT_CLONES_BASE_PATH`) +- `/tmp/git-processor/worktrees/` — per-task worktrees (`GIT_WORKTREES_BASE_PATH`) -Worktrees are removed automatically after each task finishes (controlled by `WORKTREE_RETENTION_STRATEGY`, default `always_delete`; failed-task worktrees may be retained briefly with a `.retention-info.json` marker for inspection). If disk usage grows from leftover state, stop the stack and delete stale entries under `repos/worktrees/`; cached clones can also be deleted and are re-created on the next task for that repository. +Worktrees are removed automatically after each task finishes (controlled by `WORKTREE_RETENTION_STRATEGY`, default `always_delete`; failed-task worktrees may be retained briefly with a `.retention-info.json` marker for inspection). If disk usage grows from leftover state, stop the stack and delete stale entries under the worktrees directory; cached clones can also be deleted and are re-created on the next task for that repository. ## Common Issues @@ -191,8 +191,8 @@ To remove ProPR from a host completely: rm -rf /srv/propr # or your propr-deploy directory ``` - Launcher-managed agent credentials are already below `data/`. For a native - or Compose install that used direct agent login, separately remove + Launcher-container agent credentials are already below `data/`. For a + CLI-started, native, or Compose install that used direct agent login, separately remove `~/.propr/agent-credentials` after backing up or revoking those provider accounts; do not remove the rest of `~/.propr` unless you also intend to discard other CLI state. diff --git a/docs/docs/operations/metrics.md b/docs/docs/operations/metrics.md index d4bf4f370..e6b7d30de 100644 --- a/docs/docs/operations/metrics.md +++ b/docs/docs/operations/metrics.md @@ -80,7 +80,7 @@ The API also aggregates run metrics in Redis, available at `GET /api/llm-metrics ## Cost Tracking -ProPR estimates the cost of every LLM call from its token counts (input, output, cache creation, and cache read) and per-model pricing, then stores the estimate with the call. All cost figures in the UI come from these per-call records: the LLM Log shows cost per call, and the dashboard's Total Cost is their sum. +ProPR estimates the cost of every LLM call from its token counts (input, output, cache creation, and cache read) and per-model pricing, then stores the estimate with the call. All cost figures in the UI come from these per-call records: the LLM Log shows cost per call, and the dashboard's Spend is the sum of recorded execution costs for the selected period. For directly supported Claude and OpenAI models, ProPR uses the providers' published standard API rates. Other models fall back to the OpenRouter model feed. Cache reads and cache creation are priced separately when the provider or feed publishes those rates; Claude cache creation uses the default 5-minute write rate. The token total shown beside each call includes ordinary input, output, cache creation, and cache reads, so it reconciles with the cost estimate. Provider options that change the rate but are not reported by the CLI, such as regional routing or fast mode, are not included. @@ -97,7 +97,7 @@ A cost spike should lead to an action: smaller task scope, a different model, or ### Provider capacity (Agent Tank) -Subscription plans meter capacity in session and rate-limit windows. To track those, ProPR integrates with [Agent Tank](https://agenttank.io), an optional local service that reports session and rate-limit usage for Claude, Codex, and Antigravity CLI tools. When enabled, the sidebar shows per-provider usage bars with reset countdowns, refreshed every 60 seconds, and each LLM log entry records the usage delta the call consumed. The integration is best-effort: if the service is unreachable, tasks proceed normally and the sidebar hides itself. +Subscription plans meter capacity in session and rate-limit windows. To track those, ProPR integrates with [Agent Tank](https://agenttank.io), an optional local service that reports session and rate-limit usage for Claude, Codex, and Antigravity CLI tools. When enabled, the sidebar shows per-provider usage bars with reset countdowns, which the API samples every 30 seconds and pushes when they change, and each LLM log entry records the usage delta the call consumed. The integration is best-effort: if the service is unreachable, tasks proceed normally and the sidebar hides itself. See [Agent Tank Usage Tracking](./agent-tank.md) for how to run it, connect ProPR, and read the bars. @@ -109,7 +109,7 @@ Review these signals weekly, and weight trends more heavily than one-off failure - **Per-repository health** — Repository Breakdown on `/analytics`; a repository with a below-average success rate needs attention before more work is routed to it - **Time to done** — the average processing time chart (`GET /api/stats/tasks`); individual task records show per-run duration - **Human steering effort** — average PR iterations and total follow-ups from the overview stats -- **Cost** — Total Cost, the per-model and daily breakdowns from `GET /api/llm-metrics`, and the recent high-cost alerts +- **Cost** — Spend on the dashboard, the per-model and daily breakdowns from `GET /api/llm-metrics`, and the recent high-cost alerts ### Failure analysis @@ -141,7 +141,7 @@ Between reviews, the live dashboard flags incidents: - Sudden queue growth (waiting count in queue stats) - Repeated provider rate-limit failures - Authentication failures after credential changes (agent health in the header status) -- Cost spikes (Total Cost and recent high-cost alerts) +- Cost spikes (dashboard Spend and recent high-cost alerts) - A specific repository causing disproportionate failures (Repository Breakdown on `/analytics`) - Provider capacity pressure ([Agent Tank](./agent-tank.md) usage bars, when enabled) diff --git a/docs/docs/operations/propr-connect.md b/docs/docs/operations/propr-connect.md index 3266a5e38..b9ec30b30 100644 --- a/docs/docs/operations/propr-connect.md +++ b/docs/docs/operations/propr-connect.md @@ -85,6 +85,7 @@ The acknowledgement may also carry a machine-readable `reason` (such as `unsuppo ```json { "type": "ack", + "sequence": 42, "deliveryId": "…", "status": "ignored", "reason": "user_not_allowed", @@ -212,9 +213,6 @@ source to Git. Temporary staged evidence is cleaned up after publication. Run `npm run test:visual-previews` from the repository root. This builds the shared packages and runs deterministic mocked Connect/GitHub coverage, API/settings checks, publication and log-redaction checks, and runtime-directory regression -tests. It requires no live Connect storage credentials. The same command runs on -pull requests in CI; the normal full test suite also discovers these tests. - -Keep the epic integration PR targeting `2280-epic-create-a-j2x` open for maintainer -review. Validation must not merge the epic into `main`; only maintainers explicitly -authorize that release step. The release test job has read-only repository access. +tests. It requires no live Connect storage credentials. CI does not run this +command separately: the full test suite that runs on every pull request +discovers the same tests. diff --git a/docs/docs/operations/troubleshooting.md b/docs/docs/operations/troubleshooting.md index 79f0cda18..6fa24ff01 100644 --- a/docs/docs/operations/troubleshooting.md +++ b/docs/docs/operations/troubleshooting.md @@ -103,7 +103,7 @@ Recovery runs through the PR conversation: - `/switch ` to change the PR's model going forward, or `/use ` for a one-off task with a different model. - `/review` then `/fix`, or `/ultrafix` for an automated review-fix loop (remove the `ultrafix` PR label to stop it). - Re-run with a smaller scope — see [Work Splitting](../features/work-splitting.md). -- Undo a bad commit with `propr task revert owner/repo `, which runs a signed system task (authorized via `SYSTEM_TASK_SECRET`) that resets the branch and force-pushes. +- Undo a bad commit with `propr task revert owner/repo [comment-id]`, which runs a signed system task (authorized via `SYSTEM_TASK_SECRET`) that resets the branch and force-pushes. ## Jobs Stuck In The Queue diff --git a/docs/docs/operations/web-ui-integration.md b/docs/docs/operations/web-ui-integration.md index 2907aa0e4..68597e385 100644 --- a/docs/docs/operations/web-ui-integration.md +++ b/docs/docs/operations/web-ui-integration.md @@ -38,7 +38,7 @@ The UI is not served by the API container. In both the launcher stack and the de - Browser sessions start at `GET /api/auth/github` and finish at `GET /api/auth/github/callback`. Relay-enrolled stacks use `PROPR_WEB_AUTH_MODE=connect` for local loopback URLs and hosted tunnels: Connect owns the shared GitHub OAuth client and hands the instance a short-lived one-use code. Custom deployments may use `PROPR_WEB_AUTH_MODE=github` with their own `GH_OAUTH_CLIENT_ID` and `GH_OAUTH_CLIENT_SECRET`. - Sessions are stored in Redis (`propr:session:` prefix) and sent as cookies; all frontend fetches use `credentials: 'include'`. -- All `/api/*` routes require authentication; CORS is configured from `FRONTEND_URL`. +- Operational `/api/*` routes require authentication; only the login flow, `/api/compatibility`, the desktop discovery/pairing bootstrap, and MCP (which checks its own bearer tokens) sit outside the shared guard. CORS is configured from `FRONTEND_URL`. - Bearer token authentication (GitHub tokens validated against the GitHub API, cached briefly in Redis) is enabled by default for the CLI; disable it with `ENABLE_BEARER_AUTH=false`. - `PROPR_DEMO_MODE=true` allows read-only access without login and blocks mutating requests. @@ -75,7 +75,7 @@ because of that event. | `queue:stats:update` | queue depth or throughput changes | header activity monitor | | `notification:update` | a notification is created, read or dismissed | Inbox, unread badge | | `usage:update` | agent capacity or quota changes | usage sidebar, system status | -| `activity:update` | derived from the lifecycle events above, plus the `health` domain when the instance's own health moves | header stats, shared system status (which ignores `change: 'progress'`) | +| `activity:update` | derived from the lifecycle events above, plus the `system` domain when the instance's own status snapshot moves | header stats, shared system status (which ignores `change: 'progress'`) | `activity:update` is the general envelope (`domain`, `change`, `repository`, `subjectId`, `terminal`, `occurredAt`). It is derived in @@ -138,26 +138,21 @@ above has one: (`publishNotificationUpdateThroughRedis`) and the socket service relays the event to the recipient's room. - `usage:update` is published when Agent Tank settings are saved, when a manual - re-probe succeeds, and by `packages/api/services/agentTankUsageWatcher.ts`. - Agent Tank cannot call us, so that watcher is one of the two timers left in - the system: the API probes it for the whole instance — only while a client is - connected — and publishes only when the snapshot actually moved. One backend - probe replaces the same poll in every open tab. -- `activity:update` with `domain: 'health'` is published by - `packages/api/services/systemHealthWatcher.ts`, the other remaining timer. A - worker, the daemon, Redis, GitHub authentication or a coding agent can stop - while the API and every client socket stay up, and no run lifecycle event says - so, so there is nothing to derive a health change from: the watcher compares - the same `/api/status` snapshot the clients read (the route exposes it as - `readStatusSnapshot`) against an allowlist of the health fields, ignoring the - response timestamp and routing diagnostics, and publishes only when what the - health surfaces show actually moved. The one snapshot it watches replaces the - 30-second `/api/status` poll that used to run in every open tab. - -Both watchers publish the first state they observe while a client is connected. -A client that read before the first probe may already be behind, and suppressing -that first publication would strand it: every later probe sees the same state -and stays silent, so nothing would ever correct it while its socket stays up. + re-probe succeeds, and by `packages/api/services/shellActivityBroadcaster.ts`. + Agent Tank cannot call us, so the broadcaster samples it for the whole + instance every 30 seconds — only while a client is subscribed — and publishes + only when the snapshot's fingerprint actually moved, alongside a + `shell:snapshot` frame carrying the snapshot to sockets permitted to read it. + One backend sample replaces the same poll in every open tab. +- `activity:update` with `domain: 'system'` is published by the same + broadcaster. A worker, the daemon, Redis, GitHub authentication or a coding + agent can stop while the API and every client socket stay up, and no run + lifecycle event says so, so there is nothing to derive a health change from: + the broadcaster compares the same `/api/status` snapshot the clients read + (the route exposes it as `readStatusSnapshot`) by its health fingerprint and + publishes only when what the health surfaces show actually moved. The one + snapshot it watches replaces the `/api/status` poll that used to run in every + open tab. ## Running The UI In Development diff --git a/docs/docs/tutorials/end-to-end-workflow.md b/docs/docs/tutorials/end-to-end-workflow.md index 55b1b8b73..e0af53fac 100644 --- a/docs/docs/tutorials/end-to-end-workflow.md +++ b/docs/docs/tutorials/end-to-end-workflow.md @@ -40,7 +40,7 @@ Small, specific issues produce better PRs than broad requests. 4. Open the ProPR Web UI. 5. Watch the task record. -ProPR picks up the label through its configured event intake mode — by default it receives the event near-immediately over the routing WebSocket; with `GITHUB_EVENT_INTAKE_MODE=polling` it is detected on the next polling cycle (every 60 seconds by default), and with `direct_webhook` it arrives as GitHub delivers it. As the run progresses, ProPR replaces the trigger label with state labels: `-processing` while running, then `-done` on success or a `-failed-*` label on failure. +ProPR picks up the label through its configured event intake mode — by default it receives the event near-immediately over the routing WebSocket; with `GITHUB_EVENT_INTAKE_MODE=polling` it is detected on the next polling cycle (every 60 seconds by default), and with `direct_webhook` it arrives as GitHub delivers it. As the run progresses, ProPR adds state labels alongside the trigger label: `-processing` while running, then `-done` on success or a `-failed-*` label on failure. The task record shows the selected repository, branch, model, status, logs, and resulting PR. diff --git a/docs/docs/tutorials/planner-studio.md b/docs/docs/tutorials/planner-studio.md index d54be4bb1..67fcc8026 100644 --- a/docs/docs/tutorials/planner-studio.md +++ b/docs/docs/tutorials/planner-studio.md @@ -73,11 +73,11 @@ Start execution, watch the task records in the Web UI, and review the created pu The same flow is available from the `propr` CLI: ```bash -propr plan create +propr plan create "" propr plan generate propr plan finalize propr plan abort -propr issue implement --epic --auto-merge +propr issue implement / --epic --auto-merge ``` See [ProPR CLI](../features/propr-cli.md) for the full command reference. diff --git a/docs/docs/tutorials/setup-local.md b/docs/docs/tutorials/setup-local.md index 71a0c9128..13b449ec6 100644 --- a/docs/docs/tutorials/setup-local.md +++ b/docs/docs/tutorials/setup-local.md @@ -85,10 +85,10 @@ propr init stack # creates .env + data/ logs/ repos/, detects agen `propr init stack` writes `.env` from the bundled template and auto-detects agent credential directories on the host (`~/.claude`, `~/.codex`, `~/.gemini`, `~/.config/opencode`, `~/.vibe`). The template defaults to the hosted ProPR GitHub App over WebSocket routing (`GITHUB_EVENT_INTAKE_MODE=routing_websocket`). -**2. Configure GitHub access in `.env`.** On the default path, run `propr relay enroll` from the stack directory — it opens the GitHub OAuth flow to prove your identity and writes the relay/routing credentials and `GH_INSTALLATION_ID` straight into `.env`, with no GitHub App or private key of your own. Running your own GitHub App is the advanced alternative (App permissions, `GH_APP_ID`, `GH_INSTALLATION_ID`, `HOST_GH_PRIVATE_KEY`); [GitHub Authentication](../operations/github-auth.md) covers both modes in full. +**2. Configure GitHub access in `.env`.** On the default path, install the shared ProPR GitHub App on your repositories, then run `propr login` and `propr relay enroll` from the stack directory — enrollment proves your identity with the GitHub token from `propr login` and writes the relay/routing credentials and `GH_INSTALLATION_ID` straight into `.env`, with no GitHub App or private key of your own. Running your own GitHub App is the advanced alternative (App permissions, `GH_APP_ID`, `GH_INSTALLATION_ID`, `HOST_GH_PRIVATE_KEY`); [GitHub Authentication](../operations/github-auth.md) covers both modes in full. -:::caution[Own-App path: use `HOST_GH_PRIVATE_KEY` with the CLI] -For `propr start`, point `HOST_GH_PRIVATE_KEY` at the `.pem` on the host (the CLI mounts it). `GH_PRIVATE_KEY_PATH` is the in-container path used only by the [launcher alternative](#alternative-launcher-container-without-the-cli); mixing the two is a common migration mistake. +:::caution[Own-App path: use `HOST_GH_PRIVATE_KEY`] +Point `HOST_GH_PRIVATE_KEY` at the `.pem` on the host. Both `propr start` and the [launcher alternative](#alternative-launcher-container-without-the-cli) bind-mount it into the app containers and set `GH_PRIVATE_KEY_PATH` for you. A hand-set `GH_PRIVATE_KEY_PATH` must resolve inside the app containers (for example a key staged under `data/`), so a host path or a path inside the launcher container does not work there. ::: If you take the own-App path, register the App with these repository permissions and install it on every repository ProPR should process: @@ -106,18 +106,20 @@ If you take the own-App path, register the App with these repository permissions ```bash DASHBOARD_API_PORT=4000 FRONTEND_URL=http://localhost:5173 -GH_OAUTH_CLIENT_ID=your_github_oauth_client_id -GH_OAUTH_CLIENT_SECRET=your_github_oauth_client_secret -GH_OAUTH_CALLBACK_URL=http://localhost:4000/api/auth/github/callback SESSION_SECRET=generate-a-strong-secret-here PRIMARY_PROCESSING_LABELS=AI,propr GITHUB_BOT_USERNAME=your_bot_username -GIT_CLONES_BASE_PATH=/app/repos/clones -GIT_WORKTREES_BASE_PATH=/app/repos/worktrees +GIT_CLONES_BASE_PATH=/tmp/git-processor/clones +GIT_WORKTREES_BASE_PATH=/tmp/git-processor/worktrees GIT_DEFAULT_BRANCH=main -DB_FILENAME=/app/data/propr.sqlite +DB_FILENAME=./data/propr.sqlite + +# Custom GitHub web login only; relay-enrolled stacks sign in through Connect. +# GH_OAUTH_CLIENT_ID=your_github_oauth_client_id +# GH_OAUTH_CLIENT_SECRET=your_github_oauth_client_secret +# GH_OAUTH_CALLBACK_URL=http://localhost:4000/api/auth/github/callback ``` Issue intake defaults to the hosted App's WebSocket routing: events stream to ProPR over an outbound WebSocket with near-immediate delivery, so there is no inbound public URL to expose. Polling and your own GitHub App webhook remain available as advanced intake options — see [Server Setup](./setup-server.md#github-event-intake) and [Deployment](../operations/deployment.md#issue-intake-modes). @@ -141,11 +143,11 @@ propr-deploy/ ├── your-app-private-key.pem # own-GitHub-App path only; absent on the default relay path ├── data/ # SQLite database and persistent state ├── logs/ # service logs -└── repos/ - ├── clones/ # full repository clones - └── worktrees/ # per-task Git worktrees +└── repos/ # repository mount for the worker ``` +Repository clones and per-task worktrees live outside this folder: by default under `/tmp/git-processor/clones` and `/tmp/git-processor/worktrees` on the host (`GIT_CLONES_BASE_PATH`, `GIT_WORKTREES_BASE_PATH`), a path the stack and agent containers mount at the same location. + ## Verify It Works Confirm the stack is alive before moving on: diff --git a/docs/docs/tutorials/setup-server.md b/docs/docs/tutorials/setup-server.md index d344dd833..8fc7b1dcb 100644 --- a/docs/docs/tutorials/setup-server.md +++ b/docs/docs/tutorials/setup-server.md @@ -44,14 +44,15 @@ Set the URLs in `.env` to your domain: ```bash FRONTEND_URL=https://propr.example.com +API_PUBLIC_URL=https://propr.example.com GH_OAUTH_CALLBACK_URL=https://propr.example.com/api/auth/github/callback ``` -The GitHub OAuth App callback URL must match. +`API_PUBLIC_URL` otherwise defaults to `http://localhost:4000`, which breaks auth redirects and attachment links behind a proxy. The GitHub OAuth App callback URL must match. ## GitHub Event Intake -By default ProPR receives GitHub events through the hosted ProPR GitHub App over WebSocket routing (`GITHUB_EVENT_INTAKE_MODE=routing_websocket`). Events stream to ProPR over an **outbound** WebSocket with near-immediate delivery, so a server needs **no inbound public URL** for intake and no webhook secret — the recommended path for almost every server. `propr relay enroll` provisions the shared-App install and the routing/relay credentials; see [GitHub Authentication](../operations/github-auth.md). Note that `GH_WEBHOOK_SECRET` applies only to the own-App webhook option below and is ignored in routing mode. +By default ProPR receives GitHub events through the hosted ProPR GitHub App over WebSocket routing (`GITHUB_EVENT_INTAKE_MODE=routing_websocket`). Events stream to ProPR over an **outbound** WebSocket with near-immediate delivery, so a server needs **no inbound public URL** for intake and no webhook secret — the recommended path for almost every server. Once the shared App is installed, `propr relay enroll` provisions the routing/relay credentials; see [GitHub Authentication](../operations/github-auth.md). Note that `GH_WEBHOOK_SECRET` applies only to the own-App webhook option below and is ignored in routing mode. Two advanced intake modes are available when you have a specific reason to use them: @@ -89,7 +90,7 @@ sudo mkdir -p /srv/propr && sudo chown -R "$USER":"$USER" /srv/propr && cd /srv/ propr setup --root /srv/propr # guided, re-runnable bootstrap ``` -Over SSH, run `propr setup --no-tui` if your terminal lacks raw-mode support; setup then prompts line-by-line. Choosing **Token relay** at the auth step enrolls the shared App automatically (logging you in if needed, then writing the relay/routing credentials to `.env`), so no separate `propr relay enroll` is needed. Setup is safe to re-run after editing public URLs or switching intake mode: it skips already-satisfied steps and never overwrites `.env` or deletes data. +Over SSH, run `propr setup --no-tui` if your terminal lacks raw-mode support; setup then prompts line-by-line. Choosing **ProPR Connect (default ProPR GitHub App)** at the auth step enrolls the shared App automatically (logging you in if needed, then writing the relay/routing credentials to `.env`), so no separate `propr relay enroll` is needed. Setup is safe to re-run after editing public URLs or switching intake mode: it skips already-satisfied steps and never overwrites `.env` or deletes data. ### Manual / Advanced Flow @@ -117,7 +118,6 @@ To reuse an existing Antigravity account, authenticate on the host with `agy log docker run --rm \ -v /var/run/docker.sock:/var/run/docker.sock \ -v "$PWD/.env:/app/.env:ro" \ - -v "$PWD/your-app-private-key.pem:/app/config/your-app-private-key.pem:ro" \ -e PROPR_ENV_FILE="$PWD/.env" \ -e PROPR_DATA_DIR="$PWD/data" \ -e PROPR_LOGS_DIR="$PWD/logs" \ @@ -133,7 +133,7 @@ docker run --rm \ propr/launcher:latest ``` -Omit the OpenCode and Vibe lines if you do not enable those agents. To update later, run `docker pull propr/launcher:latest` and re-run the same command. +Omit the OpenCode and Vibe lines if you do not enable those agents. If you run your own GitHub App, set `HOST_GH_PRIVATE_KEY` in `.env` to the absolute host path of the `.pem`; the launcher bind-mounts it into the app containers. To update later, run `docker pull propr/launcher:latest` and re-run the same command. ## Finish In The Web UI diff --git a/docs/docs/tutorials/setup-source.md b/docs/docs/tutorials/setup-source.md index 746a07a39..60db2da38 100644 --- a/docs/docs/tutorials/setup-source.md +++ b/docs/docs/tutorials/setup-source.md @@ -29,9 +29,11 @@ npm ci Create the credential and cache directories that agent containers mount, before the first start — Docker otherwise creates missing mount sources as root-owned, which causes write failures: ```bash -mkdir -p ~/.claude ~/.codex ~/.gemini ~/.vibe "/tmp/propr-vibe-prompts-$(id -u)" +mkdir -p ~/.claude ~/.codex ~/.gemini ~/.vibe /tmp/propr-vibe-prompts ``` +The development Compose file mounts the fixed `/tmp/propr-vibe-prompts` path; the per-user `/tmp/propr-vibe-prompts-$(id -u)` default applies only to the CLI and launcher. + Log in to each agent you plan to run (for example `claude auth login` for Claude Code, `agy login` for Antigravity) so its credential directory holds real auth state. ## 3. Configure `.env` diff --git a/docs/docs/tutorials/setup-vps.md b/docs/docs/tutorials/setup-vps.md index 31008c777..cb52163c8 100644 --- a/docs/docs/tutorials/setup-vps.md +++ b/docs/docs/tutorials/setup-vps.md @@ -303,7 +303,7 @@ Choose one auth mode: by default the shared, hosted ProPR App via the token rela HOST_GH_PRIVATE_KEY=/srv/propr/app-private-key.pem ``` -- **Shared App via relay (default)** — pick **Token relay** in `propr setup`, which enrolls and writes the relay/routing credentials to `.env` for you. To enroll standalone: +- **Shared App via relay (default)** — pick **ProPR Connect (default ProPR GitHub App)** in `propr setup`, which enrolls and writes the relay/routing credentials to `.env` for you. To enroll standalone: ```bash cd /srv/propr # run from the stack directory so the token lands in its .env @@ -315,10 +315,9 @@ Choose one auth mode: by default the shared, hosted ProPR App via the token rela *Run as: **you** (editing `/srv/propr/.env`).* -This is the step that makes the firewall meaningful. Set the API and UI ports to -bind to the loopback interface only, and set the public URLs explicitly (required -whenever you change the port form, because the auto-derived URLs assume a plain -port number). +This is the step that makes the firewall meaningful. Keep the API and UI ports +bound to the loopback interface only (the launcher default; setting them +explicitly guards against later edits), and set the public URLs explicitly. In `/srv/propr/.env`: @@ -382,10 +381,10 @@ App with its **Authorization callback URL** set to the ::: :::note[Why explicit URLs are required here] -The launcher derives `API_PUBLIC_URL`/`FRONTEND_URL` from the port value when you -don't set them (`http://localhost:`). With a `127.0.0.1:4000` port form -that derivation would produce a malformed URL, so you must set the three public -URLs above yourself. On a TLS server you would set them regardless. +The launcher derives `API_PUBLIC_URL`/`FRONTEND_URL`/`GH_OAUTH_CALLBACK_URL` from +the port values when you don't set them (`http://localhost:`). Behind a +reverse proxy those localhost URLs break sign-in redirects and links, so set the +three public URLs above yourself. ::: ## 9. Terminate TLS With A Reverse Proxy @@ -539,9 +538,10 @@ propr remote-status # backend health: daemon, workers, Redis, GitHub auth ``` Open `https://propr.example.com`, sign in with GitHub, and confirm the dashboard -loads. Note that `GITHUB_USER_WHITELIST` (step 10) gates only who can **trigger** -work from GitHub comments. To restrict who can authenticate to or view the Web UI -itself, put it +loads. `GITHUB_USER_WHITELIST` (step 10) gates both who can **trigger** work from +GitHub and who can sign in to the Web UI and API; an empty whitelist allows every +GitHub user. To keep unauthenticated traffic from reaching the application at +all, put it behind an SSO gate such as the Cloudflare Access layer in [Advanced VPS Hardening](./setup-vps-hardening.md). From a machine off the server, verify the raw ports are **not** reachable — these should both fail/time out: diff --git a/docs/docs/tutorials/setup.md b/docs/docs/tutorials/setup.md index 32e32ac1a..0466bffca 100644 --- a/docs/docs/tutorials/setup.md +++ b/docs/docs/tutorials/setup.md @@ -48,7 +48,7 @@ Access to `/var/run/docker.sock` is root-equivalent control of the host. Limit i - A host that meets the [system requirements](#system-requirements) - Node.js 22+ for the CLI path (the `propr/launcher:latest` container alternative needs no Node.js) - GitHub access for the backend. By default `propr setup` enrolls the shared, hosted ProPR GitHub App through ProPR Connect; accepting the defaults handles login through the GitHub CLI (`gh`) and installation when needed. You can instead run `propr login ` first. Running your own GitHub App is the advanced alternative. See [GitHub Authentication](../operations/github-auth.md). -- A provider account for at least one coding agent (Claude Code, Codex, Antigravity, OpenCode, or Mistral Vibe) — reuse host credentials, run `propr agent login `, or add the agent and log in directly from the Web UI +- A provider account for at least one coding agent (Claude Code, Codex, Antigravity, OpenCode, or Mistral Vibe) — reuse host credentials, run `propr agent login `, or add the agent and log in directly from the Web UI (Mistral Vibe has no interactive login; it uses `~/.vibe` or `MISTRAL_API_KEY`) - Disk space for data, logs, and repository workspaces ## Give this to your coding agent diff --git a/docs/mcp-connect-contract.md b/docs/mcp-connect-contract.md index 57d668e43..ea5dc2421 100644 --- a/docs/mcp-connect-contract.md +++ b/docs/mcp-connect-contract.md @@ -1,14 +1,8 @@ # Core / Connect MCP contract: propr-connect-mcp/1 -[Core PR #2291](https://github.com/integry/propr/pull/2291) coordinates -[the epic #2279](https://github.com/integry/propr/issues/2279), -[routing PR #180](https://github.com/integry/propr-routing/pull/180), and -[site PR #90](https://github.com/integry/propr-site/pull/90). -The shared wire contract is the **merged routing contract at -[1fcf82fd1a843fbdf199d79b8f92843dc74a89e0](https://github.com/integry/propr-routing/blob/1fcf82fd1a843fbdf199d79b8f92843dc74a89e0/docs/mcp-connect-contract.md)**. -Its `src/mcpCommon.ts`, `src/mcpGateway.ts`, `src/mcpOAuth.ts`, and -`test/fixtures/mcpInstance.ts` were inspected. This document replaces core's -incompatible proposed introspection contract. No deployment or merge is implied. +This is the instance side of the wire contract shared with the separately +maintained ProPR Connect routing service. The core implementation is complete; +the hosted gateway at `https://mcp.propr.dev` is not yet publicly available. ## Identities and endpoints @@ -178,22 +172,15 @@ Malformed array entries/preferences fail validation. An omitted legacy CIMD meth ## Executable cross-repository evidence -Run `MCP_ROUTING_REPOSITORY=/path/to/propr-routing npm run test:mcp:connect`. +With an authorized checkout of the routing service, run +`MCP_ROUTING_REPOSITORY=/path/to/routing-checkout npm run test:mcp:connect`. Optionally set `MCP_ROUTING_REVISION` to a full lowercase commit SHA to test a -private routing candidate; the merged SHA above remains the manual default. +routing candidate; otherwise the runner uses its pinned default revision. The runner verifies and archives that exact Git commit into a temporary directory, installs its lockfile, bundles its **actual Worker entry point** and runs core's actual HTTP/auth/tool implementation. It reports both source identities and SDK -versions. No routing source or policy is rewritten. See -[mcp-coverage.md](mcp-coverage.md#connect-integration-follow-up-evidence) for exact -commands, results, isolation and remaining gates. - -Core required CI runs self-contained core MCP tests. Real paired CI belongs in -the private routing repository, delegated separately as routing issue #186. -It must supply its candidate SHA and an authorized checkout and pin the public -core candidate. Root requires passing paired evidence for both exact commits -before merge. Never copy or publish private routing source/archives into core. -See [the CI division and refresh procedure](mcp-coverage.md#full-chat-follow-up-verification-and-required-ci). -Site PR #90 still needs final capability reconciliation. -Core PR #2291 and the larger full-chat epic remain open for root's independent -coverage review. No new companion task, PR, deployment or merge was started. +versions. No routing source or policy is rewritten. + +Core required CI runs self-contained core MCP tests; paired gateway coverage +runs with the routing service, not in core CI. Never copy or publish routing +source/archives into core. See [Verification in CI](mcp-coverage.md#verification-in-ci). diff --git a/docs/mcp-operator-surface.md b/docs/mcp-operator-surface.md index 553b66562..3a1dfb6fe 100644 --- a/docs/mcp-operator-surface.md +++ b/docs/mcp-operator-surface.md @@ -1,6 +1,6 @@ -# MCP operator surface (epic scaffold) +# MCP operator surface -This epic branch aggregates the work that turns ProPR's MCP server from a +This page summarizes the work that turns ProPR's MCP server from a per-object read/write catalog into a surface an operator's connected agent can actually run an instance from. @@ -37,9 +37,7 @@ The delivered capabilities are: persisted and environment-owned values, while `find_setting` explains each setting's UI, MCP, CLI or environment location and access requirements. -Each capability lands as its own pull request against this branch. The -authoritative capability mapping is `docs/mcp-coverage.md` and the operator -walkthrough is `docs/mcp.md`; both were reconciled against the shipped code in -`packages/api/mcp/` on 2026-09-30. The operator flow remains covered by +The authoritative capability mapping is `docs/mcp-coverage.md` and the operator +walkthrough is `docs/mcp.md`. The operator flow remains covered by `packages/api/test/mcpOperatorSurface.test.ts`; the combined observable contract is covered by `packages/api/test/mcpObservableSurface.test.ts`. diff --git a/docs/mcp.md b/docs/mcp.md index 6ce78da95..f3b9897be 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -13,7 +13,8 @@ and choose a scope ceiling. With `MCP_ENABLED` unset, this UI-managed path deriv an HTTPS origin from `MCP_PUBLIC_ORIGIN`, `API_PUBLIC_URL` or the GitHub callback, and derives its encryption key from `MCP_ENCRYPTION_KEY` or the existing credential, system-task or session secret chain. It persists an instance identity. Preserve -these secrets across restarts; changing the key requires reconnecting clients. +these secrets across restarts. A changed key turns MCP off (**Reconnect required**) +until an administrator revokes all connections; clients then reconnect. `MCP_ENABLED=false` forces MCP off; `true` selects the explicit environment-managed setup below. See the [illustrated connection guide](docs/features/mcp.md). @@ -54,7 +55,7 @@ Discovery endpoints: Use the exact `https://your-instance.example/api/mcp` as the OAuth `resource` in authorization, code exchange and refresh. Public clients use authorization-code + S256 PKCE. Codes last 60 seconds and are consumed -transactionally. Access tokens last five minutes. Refresh tokens rotate; +transactionally. Access tokens last 15 minutes. Refresh tokens rotate; reuse revokes the entire 30-day grant, including newly rotated access tokens. GitHub credentials are separately encrypted server-side and never returned to clients. Instance membership, allowlist and repository access are checked @@ -141,9 +142,10 @@ been exercised by the local fixture tests. ## Connect instance registration -Core [PR #2291](https://github.com/integry/propr/pull/2291) coordinates -[routing PR #180](https://github.com/integry/propr-routing/pull/180) and -[site PR #90](https://github.com/integry/propr-site/pull/90). +Connect lets public clients reach an instance through the hosted ProPR Connect +gateway at `https://mcp.propr.dev`. That hosted gateway is not yet publicly +available; this section describes the instance side, which is implemented. +Connect trust requires the environment-managed setup (`MCP_ENABLED=true`). Direct OAuth works independently of Connect trust. Hosted access uses the [implemented Connect contract](mcp-connect-contract.md). @@ -188,8 +190,8 @@ Direct OAuth works independently of Connect trust. Hosted access uses the `MCP_INSTANCE_ID` cannot overwrite an existing identity. 5. Restart the API with the matching configuration. Add each intended user through the existing Access settings and configure the allowed repositories. - Connect membership alone does not create local access. Connect a public - client to `https://mcp.propr.dev/mcp`, then explicitly select its installation, + Connect membership alone does not create local access. Once the hosted + gateway is available, connect a public client to `https://mcp.propr.dev/mcp`, then explicitly select its installation, requested permissions and repositories in the Connect browser consent flow. GitHub credential handoff happens server-to-server on the first request. @@ -205,7 +207,6 @@ The existing managed tunnel routes `/api/*`, which covers delegated MCP. It does not automatically expose direct `/.well-known`, `/authorize`, `/mcp/consent`, etc. To offer **direct OAuth through a domain**, use the complete reverse-proxy routes listed in direct setup; public Connect clients use Connect's discovery/consent. -No production configuration was changed by this PR. ## Tools and ordinary workflows @@ -214,8 +215,8 @@ The [capability matrix](mcp-coverage.md) maps supported operations to tools. permissions. Scope families are `read`, `plan`, `publish`, `execute`, `review`, `merge`, `deploy`, `manage`; scopes never grant extra GitHub or instance access. Repository restrictions are explicit lists. Administrative tools additionally -require the existing `instance.manage_settings`, `instance.manage_agents` or -`instance.manage_runtime` permission. Goal and plan ownership is preserved. +require the existing `instance.manage_settings`, `instance.manage_agents`, +`instance.manage_runtime` or `instance.manage_members` permission. Goal and plan ownership is preserved. Ordinary repository task history follows the existing shared repository model; native goal tasks remain private and can only be mutated through goal controls. @@ -363,8 +364,9 @@ corresponding `get_*` tool without inflating large list pages. defaults to the 20 most recent entries and returns newest-first, timestamped pages with `nextOffset` for older narration. Each entry is whitespace-normalized and capped at 500 characters. The feed includes assistant progress commentary -and a separate current-focus value when available; provider reasoning, raw +and a separate current-focus value when available; raw provider reasoning, raw protocol envelopes, tool inputs, and tool results are excluded. +`includeReasoningSummaries: true` opts in to Codex app-server reasoning summaries. ## Operating an instance from a chat client @@ -471,7 +473,7 @@ list — undetermined, not absent. Then read the discussion newest-first: with their `currentFindingIds`, `reviewedHead` and `matchesCurrentHead`, and a `nextCursor` for older comments. Comment prose is untrusted data. -**4. Act on it, at an exact head.** The append-only +**4. Act on it at a known head.** The append-only `review_pull_request`, `fix_review_findings`, `run_ultrafix` and `comment_on_pull_request` tools make `expectedHead` optional. When it is omitted, the tool uses the current head from its own pull-request read and @@ -603,7 +605,8 @@ shows the same activity per app as a last-used time and a 24-hour request count. ## Resources, prompts, text and voice Resource URIs use `propr://instances/{instance_id}/`: `connection`, -`repositories`, `models`, `activity`, `activity/recent`, `plans/{id}`, +`repositories`, `models`, `notifications`, `notifications/{id}`, `activity`, +`activity/recent`, `plans/{id}`, `goals/{id}`, `tasks/{id}`, `changes/{task_id}`, `repositories/{owner}/{repo}`, `repositories/{owner}/{repo}/pulls`, `repositories/{owner}/{repo}/pulls/{number}`, `submissions/{id}`, @@ -693,9 +696,3 @@ partial publication/implementation, an operator must reconcile the receipt, GitHub markers, issue labels and queue state before explicitly recovering it. No deployment, auto-merge activation or production migration was performed. - -The Connect follow-up also runs both actual repositories at the pinned routing -commit, including registration, public OAuth, both SDK eras and proof-bound -credential handoff. Exact commands/results and the remaining full-chat gates -are in [the follow-up evidence](mcp-coverage.md#connect-integration-follow-up-evidence). -Earlier test counts above describe the original PR baseline, not the follow-up. diff --git a/packages/api/test/mcpObservableSurface.test.ts b/packages/api/test/mcpObservableSurface.test.ts index 2e520d312..388ee764b 100644 --- a/packages/api/test/mcpObservableSurface.test.ts +++ b/packages/api/test/mcpObservableSurface.test.ts @@ -292,7 +292,7 @@ test('observable MCP surface keeps receipts, errors, overview, docs and previews 'executing', 'failed', 'format', 'generating', 'github', 'goal_reached', 'head', 'instruction', 'instructions', 'internal', 'iss', 'issue_created', 'items', 'kind', 'labels', 'limit', 'manage', 'mcp_access_log', 'mcp_operations', 'mcp_records', 'merge', 'merged', 'message', 'model', 'models', - 'name', 'node', 'none', 'null', 'number', 'offset', 'outcome', 'page', 'path', 'plan', 'plan_issues', + 'name', 'node', 'none', 'notifications', 'null', 'number', 'offset', 'outcome', 'page', 'path', 'plan', 'plan_issues', 'posted', 'pr_created', 'precondition', 'private_key_jwt', 'progress', 'prompt', 'propr', 'publish', 'queue', 'queued', 'read', 'refining', 'repositories', 'repository', 'resource', 'retryable', 'review', 'role', 'running', 'section', 'since', 'stage', 'state', 'status', 'stopped', 'submitted', 'success', 'true',