Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions docs/docs/architecture/agent-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.

Expand All @@ -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.
Expand Down Expand Up @@ -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 <id>] --max-turns N --output-format stream-json --verbose --dangerously-skip-permissions
claude -p - --no-session-persistence [--model <id>] --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.
Expand All @@ -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
Expand All @@ -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 <id>`. 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.
Expand Down
29 changes: 12 additions & 17 deletions docs/docs/architecture/daemon.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -29,7 +29,7 @@ It should stay lightweight. The daemon decides what should be processed; workers
<div className="propr-flow__connector">↓</div>
<div className="propr-flow__node"><span className="propr-flow__title">Find eligible issues or PR events</span></div>
<div className="propr-flow__connector">↓</div>
<div className="propr-flow__node"><span className="propr-flow__title">Resolve labels, repository config, and models</span></div>
<div className="propr-flow__node"><span className="propr-flow__title">Resolve trigger labels and repository config</span></div>
<div className="propr-flow__connector">↓</div>
<div className="propr-flow__node"><span className="propr-flow__title">Skip work already processing or completed</span></div>
<div className="propr-flow__connector">↓</div>
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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-<owner>-<repo>-<number>
```

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-<owner>-<repo>-<number>-<agent>-<model>
issue-<owner>-<repo>-<number>-<agent>-<model>-<base-branch>
```

## 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

Expand All @@ -135,7 +130,7 @@ POLLING_INTERVAL_MS=60000
# Label configuration
PRIMARY_PROCESSING_LABELS=AI,propr
MODEL_LABEL_PATTERN=^llm-(.+)$
DEFAULT_MODEL_NAME=<model-id-used-when-no-llm-label-is-present>
DEFAULT_CLAUDE_MODEL=<model-id-used-when-no-llm-label-is-present>

# Event intake mode: routing_websocket (default), polling, or direct_webhook.
# GH_WEBHOOK_SECRET applies only to direct_webhook (your own GitHub App).
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/architecture/git-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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_<OWNER>_<REPO>` 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.

Expand Down
4 changes: 2 additions & 2 deletions docs/docs/architecture/git-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down
4 changes: 4 additions & 0 deletions docs/docs/architecture/preview-storage-relay.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion docs/docs/architecture/worker-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/architecture/worker.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/concepts/repository-best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Loading
Loading