loreli 0.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +710 -97
- package/bin/loreli.js +89 -0
- package/package.json +77 -14
- package/packages/README.md +101 -0
- package/packages/action/README.md +98 -0
- package/packages/action/prompts/action.md +172 -0
- package/packages/action/src/index.js +684 -0
- package/packages/agent/README.md +606 -0
- package/packages/agent/src/backends/claude.js +387 -0
- package/packages/agent/src/backends/codex.js +351 -0
- package/packages/agent/src/backends/cursor.js +371 -0
- package/packages/agent/src/backends/index.js +486 -0
- package/packages/agent/src/base.js +138 -0
- package/packages/agent/src/cli.js +275 -0
- package/packages/agent/src/discover.js +396 -0
- package/packages/agent/src/factory.js +124 -0
- package/packages/agent/src/index.js +12 -0
- package/packages/agent/src/models.js +159 -0
- package/packages/agent/src/output.js +62 -0
- package/packages/agent/src/session.js +162 -0
- package/packages/agent/src/trace.js +186 -0
- package/packages/classify/README.md +136 -0
- package/packages/classify/prompts/blocker.md +12 -0
- package/packages/classify/prompts/feedback.md +14 -0
- package/packages/classify/prompts/pane-state.md +20 -0
- package/packages/classify/src/index.js +81 -0
- package/packages/config/README.md +898 -0
- package/packages/config/src/defaults.js +145 -0
- package/packages/config/src/index.js +223 -0
- package/packages/config/src/schema.js +291 -0
- package/packages/config/src/validate.js +160 -0
- package/packages/context/README.md +165 -0
- package/packages/context/src/index.js +198 -0
- package/packages/hub/README.md +338 -0
- package/packages/hub/src/base.js +154 -0
- package/packages/hub/src/github.js +1597 -0
- package/packages/hub/src/index.js +79 -0
- package/packages/hub/src/labels.js +48 -0
- package/packages/identity/README.md +288 -0
- package/packages/identity/src/index.js +620 -0
- package/packages/identity/src/themes/avatar.js +217 -0
- package/packages/identity/src/themes/digimon.js +217 -0
- package/packages/identity/src/themes/dragonball.js +217 -0
- package/packages/identity/src/themes/lotr.js +217 -0
- package/packages/identity/src/themes/marvel.js +217 -0
- package/packages/identity/src/themes/pokemon.js +217 -0
- package/packages/identity/src/themes/starwars.js +217 -0
- package/packages/identity/src/themes/transformers.js +217 -0
- package/packages/identity/src/themes/zelda.js +217 -0
- package/packages/knowledge/README.md +217 -0
- package/packages/knowledge/src/index.js +243 -0
- package/packages/log/README.md +93 -0
- package/packages/log/src/index.js +252 -0
- package/packages/marker/README.md +200 -0
- package/packages/marker/src/index.js +184 -0
- package/packages/mcp/README.md +323 -0
- package/packages/mcp/instructions.md +126 -0
- package/packages/mcp/scaffolding/.agents/skills/loreli-context/SKILL.md +89 -0
- package/packages/mcp/scaffolding/ISSUE_TEMPLATE/config.yml +2 -0
- package/packages/mcp/scaffolding/ISSUE_TEMPLATE/loreli.yml +83 -0
- package/packages/mcp/scaffolding/loreli.yml +491 -0
- package/packages/mcp/scaffolding/mcp-configs/.codex/config.toml +4 -0
- package/packages/mcp/scaffolding/mcp-configs/.cursor/mcp.json +14 -0
- package/packages/mcp/scaffolding/mcp-configs/.mcp.json +14 -0
- package/packages/mcp/scaffolding/pull-request.md +23 -0
- package/packages/mcp/src/index.js +600 -0
- package/packages/mcp/src/tools/agent-context.js +44 -0
- package/packages/mcp/src/tools/agents.js +450 -0
- package/packages/mcp/src/tools/context.js +200 -0
- package/packages/mcp/src/tools/github.js +1163 -0
- package/packages/mcp/src/tools/hitl.js +162 -0
- package/packages/mcp/src/tools/index.js +18 -0
- package/packages/mcp/src/tools/refactor.js +227 -0
- package/packages/mcp/src/tools/repo.js +44 -0
- package/packages/mcp/src/tools/start.js +904 -0
- package/packages/mcp/src/tools/status.js +149 -0
- package/packages/mcp/src/tools/work.js +134 -0
- package/packages/orchestrator/README.md +192 -0
- package/packages/orchestrator/src/index.js +1492 -0
- package/packages/planner/README.md +251 -0
- package/packages/planner/prompts/plan-reviewer.md +109 -0
- package/packages/planner/prompts/planner.md +191 -0
- package/packages/planner/prompts/tiebreaker-reviewer.md +71 -0
- package/packages/planner/src/index.js +1381 -0
- package/packages/review/README.md +129 -0
- package/packages/review/prompts/reviewer.md +158 -0
- package/packages/review/src/index.js +1403 -0
- package/packages/risk/README.md +178 -0
- package/packages/risk/prompts/risk.md +272 -0
- package/packages/risk/src/index.js +439 -0
- package/packages/session/README.md +165 -0
- package/packages/session/src/index.js +215 -0
- package/packages/test-utils/README.md +96 -0
- package/packages/test-utils/src/index.js +354 -0
- package/packages/tmux/README.md +261 -0
- package/packages/tmux/src/index.js +501 -0
- package/packages/workflow/README.md +317 -0
- package/packages/workflow/prompts/preamble.md +14 -0
- package/packages/workflow/src/index.js +660 -0
- package/packages/workflow/src/proof-of-life.js +74 -0
- package/packages/workspace/README.md +143 -0
- package/packages/workspace/src/index.js +1127 -0
- package/index.js +0 -8
package/README.md
CHANGED
|
@@ -1,102 +1,715 @@
|
|
|
1
1
|
# Loreli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
###
|
|
82
|
-
|
|
83
|
-
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
3
|
+
Agentic team orchestration via GitHub.
|
|
4
|
+
|
|
5
|
+
Loreli is an MCP server that coordinates AI agents using GitHub's native collaboration primitives — issues for tasks, pull requests for deliverables, discussions for plans, comments for communication, and reviews for quality gates. The name combines **Lore** (creating project lore through GitHub artifacts) and **CLI** (exposed as a command-line tool via MCP).
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
This guide walks you through setting up Loreli from scratch — from creating a GitHub token to watching your first agent team work on an issue.
|
|
10
|
+
|
|
11
|
+
### 1. Prerequisites
|
|
12
|
+
|
|
13
|
+
Before installing Loreli, make sure you have the following:
|
|
14
|
+
|
|
15
|
+
| Requirement | How to check | Install |
|
|
16
|
+
|-------------|-------------|---------|
|
|
17
|
+
| **macOS or Linux** | `uname -s` | Windows is not supported |
|
|
18
|
+
| **Node.js >= 24** | `node --version` | `nvm install 24` or `brew install node@24` |
|
|
19
|
+
| **tmux** | `tmux -V` | `brew install tmux` (macOS) or `apt install tmux` (Linux) |
|
|
20
|
+
| **At least one agent backend** | See table below | Depends on provider |
|
|
21
|
+
|
|
22
|
+
tmux is required for all agent backends (Claude, Codex, Cursor). If tmux is missing, `loreli mcp` exits immediately with install instructions.
|
|
23
|
+
Loreli supports macOS and Linux only. Windows is not supported.
|
|
24
|
+
|
|
25
|
+
**Agent backend CLIs** — install one or more depending on which AI providers you want to use:
|
|
26
|
+
|
|
27
|
+
| Backend | Binary | Install | Provider |
|
|
28
|
+
|---------|--------|---------|----------|
|
|
29
|
+
| Claude | `claude` | [Anthropic CLI](https://docs.anthropic.com/en/docs/claude-code/overview) | Anthropic |
|
|
30
|
+
| Codex | `codex` | [OpenAI Codex CLI](https://github.com/openai/codex) | OpenAI |
|
|
31
|
+
| Cursor | `cursor-agent` | [Cursor Agent](https://docs.cursor.com/agent) | Multi-provider |
|
|
32
|
+
|
|
33
|
+
Loreli auto-discovers which backends are available on your `PATH` at startup.
|
|
34
|
+
|
|
35
|
+
### 2. Create a GitHub Token
|
|
36
|
+
|
|
37
|
+
Loreli needs a GitHub Personal Access Token (PAT) with permission to manage issues, pull requests, discussions, labels, and repository contents.
|
|
38
|
+
|
|
39
|
+
**Create a classic PAT:**
|
|
40
|
+
|
|
41
|
+
1. Go to [github.com/settings/tokens](https://github.com/settings/tokens)
|
|
42
|
+
2. Click **Generate new token** > **Generate new token (classic)**
|
|
43
|
+
3. Give it a descriptive name (e.g. `loreli-orchestration`)
|
|
44
|
+
4. Set an expiration (or "No expiration" for long-running setups)
|
|
45
|
+
5. Under **Select scopes**, check **`repo`** — this single scope covers everything Loreli needs: issues, PRs, labels, discussions, reviews, repo contents, and merge
|
|
46
|
+
6. Click **Generate token** and copy it immediately — GitHub will not show it again
|
|
47
|
+
|
|
48
|
+
**Set the token in your environment:**
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
export GITHUB_TOKEN=ghp_your_token_here
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
To persist it, add the export to your shell profile (`~/.zshrc`, `~/.bashrc`) or create a `.env` file in the project root. Never commit tokens to version control.
|
|
55
|
+
> 🔐 **Secret handling** — Personal access tokens carry the same blast radius as your GitHub account. Keep them in environment variables or a secret manager, scope them to the minimum permissions, and rotate them regularly. See [GitHub’s “Keeping your API credentials secure” guidance](https://docs.github.com/en/rest/authentication/keeping-your-api-credentials-secure) for the official checklist.
|
|
56
|
+
|
|
57
|
+
<details>
|
|
58
|
+
<summary>Using a fine-grained token instead</summary>
|
|
59
|
+
|
|
60
|
+
Fine-grained PATs work but require enabling each permission explicitly. Go to [github.com/settings/personal-access-tokens/new](https://github.com/settings/personal-access-tokens/new) and grant **Read and Write** access for:
|
|
61
|
+
|
|
62
|
+
- **Contents** — reading/writing repo files
|
|
63
|
+
- **Issues** — creating/managing issues and comments
|
|
64
|
+
- **Pull requests** — creating PRs, requesting reviews, merging
|
|
65
|
+
- **Discussions** — creating plan discussions and comments
|
|
66
|
+
- **Metadata** — read-only (required by GitHub for all fine-grained tokens)
|
|
67
|
+
|
|
68
|
+
Set the **Resource owner** and **Repository access** to match the repos you plan to orchestrate.
|
|
69
|
+
</details>
|
|
70
|
+
|
|
71
|
+
### 3. Install Loreli
|
|
72
|
+
|
|
73
|
+
Run the command below to install the `loreli` CLI globally so your MCP client can start the server; the install should complete without npm errors.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install -g loreli
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Hold off on running `loreli` commands until you've completed Step 4, because the CLI relies on the MCP server entry being configured.
|
|
80
|
+
|
|
81
|
+
### 4. Configure Your MCP Client
|
|
82
|
+
|
|
83
|
+
Loreli runs as an MCP server over stdio. Your IDE or MCP client needs a config entry that tells it how to start Loreli. Add this to your **global** (user-level) MCP settings so the token stays out of project files.
|
|
84
|
+
|
|
85
|
+
Before editing any config file:
|
|
86
|
+
|
|
87
|
+
1. Export `GITHUB_TOKEN` in the shell or source it from a local `.env` so the value never lands in Git history.
|
|
88
|
+
2. Use your client’s environment forwarding rather than pasting literals. Cursor and VS Code expand `${env:NAME}` placeholders inside `mcpServers` blocks, while Claude’s `.mcp.json` honors `${NAME}` tokens per the [Cursor MCP docs](https://docs.cursor.com/ko/context/mcp), [VS Code variable reference](https://code.visualstudio.com/docs/editor/variables-reference), and [Claude Code MCP guide](https://docs.claude.ai/claude-code/mcp).
|
|
89
|
+
3. Keep repo-level `loreli.yml` and workspace configs secret-free; only user-level config or wrapper scripts should reference tokens.
|
|
90
|
+
|
|
91
|
+
**Cursor / VS Code** — open **Settings** > search **MCP** > **Edit in settings.json**, or add directly to your user-level `~/.cursor/mcp.json`:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"loreli": {
|
|
97
|
+
"command": "npx",
|
|
98
|
+
"args": ["loreli", "mcp"],
|
|
99
|
+
"env": {
|
|
100
|
+
"GITHUB_TOKEN": "${env:GITHUB_TOKEN}"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Cursor and VS Code both expand `${env:NAME}` placeholders, so this entry reads the token you already exported (`export GITHUB_TOKEN=...`) without storing it in the config. Cursor additionally supports an `envFile` attribute if you prefer pointing at a dedicated `.env` file that lives outside your repos (see the [Cursor MCP docs](https://docs.cursor.com/ko/context/mcp) for the full schema).
|
|
108
|
+
|
|
109
|
+
**Claude Code (CLI)** — add to your user-level config at `~/.claude/.mcp.json`:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"loreli": {
|
|
115
|
+
"command": "npx",
|
|
116
|
+
"args": ["loreli", "mcp"],
|
|
117
|
+
"env": {
|
|
118
|
+
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The `env` block keeps the token scoped to Loreli's process, and Claude expands `${VAR}` placeholders at load time per the [Claude Code MCP guide](https://docs.claude.ai/claude-code/mcp#environment-variable-expansion), so you only need to manage the token in your shell. Alternatively, if `GITHUB_TOKEN` is already exported in your shell profile, you can omit the `env` block entirely — Loreli reads `process.env.GITHUB_TOKEN` at startup.
|
|
126
|
+
|
|
127
|
+
<details>
|
|
128
|
+
<summary>Claude Desktop</summary>
|
|
129
|
+
|
|
130
|
+
Add to your Claude Desktop config file:
|
|
131
|
+
|
|
132
|
+
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"mcpServers": {
|
|
137
|
+
"loreli": {
|
|
138
|
+
"command": "npx",
|
|
139
|
+
"args": ["loreli", "mcp"],
|
|
140
|
+
"env": {
|
|
141
|
+
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Claude Desktop shares the same `.mcp.json` schema as the CLI, so `${GITHUB_TOKEN}` resolves against the environment variable available when the desktop app launches. Keep the variable in your login shell or macOS Keychain-backed launch script instead of copying the literal token into this file.
|
|
149
|
+
</details>
|
|
150
|
+
|
|
151
|
+
<details>
|
|
152
|
+
<summary>Codex CLI</summary>
|
|
153
|
+
|
|
154
|
+
Add to `~/.codex/config.toml` (user-level):
|
|
155
|
+
|
|
156
|
+
```toml
|
|
157
|
+
[mcp_servers.loreli]
|
|
158
|
+
command = "npx"
|
|
159
|
+
args = ["loreli", "mcp"]
|
|
160
|
+
env_vars = ["GITHUB_TOKEN"]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Codex only forwards a short built-in whitelist of environment variables to STDIO MCP servers; anything sensitive like `GITHUB_TOKEN` must be explicitly listed in `env_vars` so the CLI copies it from your shell into the Loreli process without writing the value to disk. Once you add the line above and export `GITHUB_TOKEN` in your shell, Codex will pass it through on launch per the [Codex config reference](https://developers.openai.com/codex/config-reference) and [docs/example-config](https://fossies.org/linux/codex-rust/docs/example-config.md).
|
|
164
|
+
</details>
|
|
165
|
+
|
|
166
|
+
To confirm your MCP configuration is discoverable by the CLI, run the commands below in a shell where `GITHUB_TOKEN` is set. This matters because the CLI resolves tool calls through the MCP server entry, and without it even `loreli --version` and `loreli tools list` will fail. You should see the version string and a list of available tools.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
loreli --version
|
|
170
|
+
loreli tools list # should print all available MCP tools
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 5. Prepare Your Repository
|
|
174
|
+
|
|
175
|
+
Before Loreli can orchestrate work on a repo, three things need to be in place: GitHub Discussions enabled, a "Loreli" discussion category, and a start run.
|
|
176
|
+
|
|
177
|
+
**Step 1: Enable GitHub Discussions**
|
|
178
|
+
|
|
179
|
+
1. Go to your repository on GitHub
|
|
180
|
+
2. Navigate to **Settings** > **General**
|
|
181
|
+
3. Scroll down to the **Features** section
|
|
182
|
+
4. Check the **Discussions** checkbox
|
|
183
|
+
|
|
184
|
+
**Step 2: Create the "Loreli" discussion category**
|
|
185
|
+
|
|
186
|
+
Loreli uses a dedicated discussion category for planning. GitHub's API does not support creating discussion categories, so this is the one manual step that cannot be automated.
|
|
187
|
+
|
|
188
|
+
1. Go to your repository's **Discussions** tab
|
|
189
|
+
2. Click the pencil icon next to **Categories** in the left sidebar
|
|
190
|
+
3. Click **New category**
|
|
191
|
+
4. Fill in the form:
|
|
192
|
+
- **Category name**: `Loreli` (exact spelling, case-sensitive)
|
|
193
|
+
- **Description**: `Loreli agent orchestration plans`
|
|
194
|
+
- **Discussion Format**: Open-ended discussion
|
|
195
|
+
5. Click **Create**
|
|
196
|
+
|
|
197
|
+
**Step 3: Start the repository**
|
|
198
|
+
|
|
199
|
+
With your MCP client connected, call the `start` tool:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
start({ repo: "owner/repo-name" })
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Or from the CLI:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
loreli tools start --repo owner/repo-name
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Start is idempotent — safe to re-run at any time. It discovers existing files and only creates what's missing. Here's what it does:
|
|
212
|
+
|
|
213
|
+
| Action | Details |
|
|
214
|
+
|--------|---------|
|
|
215
|
+
| **Scaffolds templates** | PR template, issue templates, `loreli.yml` config |
|
|
216
|
+
| **Configures MCP** | Adds loreli server entry to `.mcp.json`, `.cursor/mcp.json`, `.codex/config.toml` |
|
|
217
|
+
| **Creates labels** | `loreli`, `loreli:planner`, `loreli:action`, `loreli:reviewer`, `loreli:approved`, `loreli:changes-requested`, plus per-provider labels |
|
|
218
|
+
| **Adds dependency** | Ensures `loreli` is in `devDependencies` of `package.json` |
|
|
219
|
+
| **Updates .gitignore** | Adds rules for `.loreli/`, `.claude/`, `.cursor/hooks.json` |
|
|
220
|
+
| **Starts reactor** | Begins the orchestration loop that watches for work |
|
|
221
|
+
|
|
222
|
+
After start, you'll see a summary of the session, detected backends, review strategy, and any files that were scaffolded.
|
|
223
|
+
|
|
224
|
+
### 6. Your First Run
|
|
225
|
+
|
|
226
|
+
With everything set up, here's the quickest path to seeing Loreli in action:
|
|
227
|
+
|
|
228
|
+
**Create a labeled issue** on your repository with the `loreli` label. The issue body should describe a task — for example:
|
|
229
|
+
|
|
230
|
+
> **Title**: Add a hello world endpoint
|
|
231
|
+
>
|
|
232
|
+
> **Body**: Create a simple `/hello` endpoint that returns `{ "message": "Hello, world!" }`. Add a basic test.
|
|
233
|
+
>
|
|
234
|
+
> **Label**: `loreli`
|
|
235
|
+
|
|
236
|
+
**Watch the system react.** The reactor loop (every 60 seconds) detects the unclaimed issue, spawns an action agent, and assigns it. Use `team_status` to monitor progress:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
team_status()
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The action agent claims the issue, creates a branch, implements the work, and opens a PR. Loreli then auto-spawns a reviewer. In dual-side environments, review is cross-provider (yin vs yang). In single-side environments, Loreli falls back to same-provider review with distinct action/reviewer identities. After approval, the PR is either auto-merged or handed to human reviewers (depending on your `loreli.yml` configuration).
|
|
243
|
+
|
|
244
|
+
For planning-driven work, use `start_planning` with an objective instead — Loreli will create plan discussions, run adversarial review, and promote approved plans into issues that enter the same reactive loop.
|
|
245
|
+
|
|
246
|
+
## Package and Development Docs
|
|
247
|
+
|
|
248
|
+
This README is intentionally focused on operating Loreli as a consumer.
|
|
249
|
+
|
|
250
|
+
For internal architecture, subpackage import docs (`loreli/*`), and contributor/development workflows, see [`packages/README.md`](packages/README.md).
|
|
251
|
+
For topology-aware end-to-end testing (`pnpm e2e`, `pnpm e2e:single`, `pnpm e2e:multi`), see [`e2e/README.md`](e2e/README.md).
|
|
252
|
+
|
|
253
|
+
## Agent Workflow
|
|
254
|
+
|
|
255
|
+
Start starts the reactor loop automatically. Once started, the system is fully reactive — agents are spawned on demand when work appears on GitHub and reaped when idle. Any machine running a Loreli MCP is part of the distributed system.
|
|
256
|
+
|
|
257
|
+
```mermaid
|
|
258
|
+
sequenceDiagram
|
|
259
|
+
participant User as User / Parent Agent
|
|
260
|
+
participant L as Loreli MCP
|
|
261
|
+
participant Orch as Orchestrator
|
|
262
|
+
participant A as Action Agent
|
|
263
|
+
participant R as Review Agent
|
|
264
|
+
participant GH as GitHub
|
|
265
|
+
|
|
266
|
+
User->>L: start(repo)
|
|
267
|
+
L->>GH: discover + scaffold
|
|
268
|
+
Note over Orch: Reactor starts (60s tick)
|
|
269
|
+
User->>GH: Create issue with loreli label
|
|
270
|
+
Note over Orch: Tick detects unclaimed issue
|
|
271
|
+
Orch->>A: Auto-spawn action agent
|
|
272
|
+
A->>GH: Claim issue + create PR
|
|
273
|
+
Orch->>R: Auto-spawn reviewer (opposing side when available)
|
|
274
|
+
R->>GH: Review PR (adversarial)
|
|
275
|
+
A->>GH: Address feedback
|
|
276
|
+
R->>GH: Approve + sign off
|
|
277
|
+
A->>GH: Sign off
|
|
278
|
+
alt auto-merge
|
|
279
|
+
Orch->>GH: Merge PR
|
|
280
|
+
else HITL
|
|
281
|
+
L->>GH: Request human review
|
|
282
|
+
Orch->>Orch: Kill agents
|
|
283
|
+
end
|
|
284
|
+
Note over Orch: Reap idle agents
|
|
285
|
+
Note over Orch: Next tick — repeat
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
1. **Start** — Point Loreli at a GitHub repo. It discovers existing files, scaffolds any missing ones, and starts the reactor loop. This is idempotent — safe to re-run. Starting the MCP means joining the distributed system.
|
|
289
|
+
2. **Reactive dispatch** — The reactor tick (every 60s) checks for unclaimed `loreli`-labeled issues. When work is found and no agents are available, an action agent is auto-spawned. Humans or agents can call `add_agent` for additional capacity.
|
|
290
|
+
3. **Action** — Action agents claim issues (first-comment-wins), create git worktree branches, implement work, and open PRs.
|
|
291
|
+
4. **Review** — Reviewers are auto-enlisted when PRs appear. With dual-side capability, Loreli enforces cross-provider review. With single-side capability, Loreli allows same-provider review using a distinct reviewer identity.
|
|
292
|
+
5. **Human In The Loop (HITL)** (optional) — If `reviewers` are configured in `loreli.yml`, PRs are handed off to human reviewers after agent approval. Agents are shut down while awaiting human decision.
|
|
293
|
+
6. **Merge** — Approval from an eligible reviewer triggers auto-merge, or human merges manually.
|
|
294
|
+
7. **Reap** — When no open issues or PRs remain, idle agents are killed. The cycle repeats on the next tick if new work arrives.
|
|
295
|
+
|
|
296
|
+
**Planning** is an explicit step — call `start_planning(objective)` with planner agents to create plan discussions. Plans are reviewed, revised, and promoted to issues, which then enter the reactive dispatch loop above.
|
|
297
|
+
|
|
298
|
+
## Agent Death Snapshots
|
|
299
|
+
|
|
300
|
+
When an agent's process exits — whether from completion, crash, or forced kill — Loreli captures the terminal output before destroying the tmux pane. These snapshots are written to the session's log directory:
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
~/.loreli/sessions/<sessionId>/logs/
|
|
304
|
+
optimus-0.death.log
|
|
305
|
+
megatron-0.death.log
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
All interactive agents have `remain-on-exit` set on their tmux pane automatically, so output survives after the process exits. The orchestrator calls `snapshot()` before `agent.stop()` in every exit path (`reconcile`, `kill`, `shutdown`).
|
|
309
|
+
|
|
310
|
+
Death snapshots are cleaned up by `Storage.prune()` alongside other session data when the session expires (default: 12 hours, configurable via `cleanup.retention`).
|
|
311
|
+
|
|
312
|
+
## Agent Backends
|
|
313
|
+
|
|
314
|
+
Loreli supports multiple agent backends. The `BackendRegistry` auto-discovers which are available at startup, including available models for backends that support runtime discovery.
|
|
315
|
+
|
|
316
|
+
| Backend | CLI Binary | Provider | Model Discovery |
|
|
317
|
+
|---------|-----------|----------|----------------|
|
|
318
|
+
| Claude | `claude` | Anthropic | Proxy listing (`/v1/models` or `/models`) when `ANTHROPIC_BASE_URL` is configured; otherwise static defaults |
|
|
319
|
+
| Cursor | `cursor-agent` | Multi-provider | `--list-models` with auto tier classification |
|
|
320
|
+
| Codex | `codex` | OpenAI | Proxy listing (`/v1/models` or `/models`) when `OPENAI_BASE_URL` is configured; otherwise static defaults |
|
|
321
|
+
|
|
322
|
+
Model aliases (`fast`, `balanced`, `powerful`) resolve through: config override > runtime discovery > static defaults > pass-through. See [packages/agent/README.md](packages/agent/README.md) for the full resolution chain and LiteLLM/proxy override docs.
|
|
323
|
+
|
|
324
|
+
Loreli derives review strategy from detected side capability at runtime:
|
|
325
|
+
|
|
326
|
+
- **Dual-side** (yin + yang detected): cross-provider review and merge gating.
|
|
327
|
+
- **Single-side** (only yin or only yang detected): fresh-instance same-provider review with distinct identities.
|
|
328
|
+
|
|
329
|
+
## Configuration
|
|
330
|
+
|
|
331
|
+
Each target repository can have a `loreli.yml` in its root. If absent, start scaffolds a default one with all options documented.
|
|
332
|
+
|
|
333
|
+
```yaml
|
|
334
|
+
# loreli.yml — key settings
|
|
335
|
+
theme: transformers # string or list of themes (randomized per work item)
|
|
336
|
+
# theme: # use a list to randomize:
|
|
337
|
+
# - transformers
|
|
338
|
+
# - pokemon
|
|
339
|
+
# - marvel
|
|
340
|
+
reviewers: [] # GitHub usernames; empty = auto-merge
|
|
341
|
+
merge:
|
|
342
|
+
method: squash # squash | merge | rebase
|
|
343
|
+
hitl: false # false = auto-merge, true = human reviewers
|
|
344
|
+
base: loreli # agents PR against this branch, not main
|
|
345
|
+
pr:
|
|
346
|
+
validation:
|
|
347
|
+
command: npm test # default pre-PR command; blocks pr/create on failure
|
|
348
|
+
selfReview:
|
|
349
|
+
enabled: true # default: pr/create requires preview + confirm=true
|
|
350
|
+
model: balanced # fast | balanced | powerful (global fallback)
|
|
351
|
+
labels:
|
|
352
|
+
track: true # enable provider/model label tracking
|
|
353
|
+
extra: [] # additional labels applied to all loreli items
|
|
354
|
+
timeouts:
|
|
355
|
+
stall: "10m" # human-readable before agent is considered stalled
|
|
356
|
+
shutdown: "1m" # graceful shutdown before kill
|
|
357
|
+
poll: "2s" # orchestrator poll interval
|
|
358
|
+
rapidDeath: "15s" # startup crash detection window
|
|
359
|
+
proxyDiscovery: "5s" # HTTP timeout for proxy model discovery
|
|
360
|
+
nudge: true # enable tier-1 stall nudge messages
|
|
361
|
+
watch:
|
|
362
|
+
interval: "60s" # reactor tick interval
|
|
363
|
+
maxRounds: 7 # max review rounds before escalation
|
|
364
|
+
trace:
|
|
365
|
+
enabled: true # include agent trace blocks in PR bodies/reviews
|
|
366
|
+
includeOutput: true # include captured terminal output in trace
|
|
367
|
+
maxOutputChars: 8000 # truncate output beyond this limit
|
|
368
|
+
agents:
|
|
369
|
+
disallowedTools: # CLI tools denied in agent workspaces
|
|
370
|
+
- gh
|
|
371
|
+
- curl
|
|
372
|
+
workflows: # per-role model, scaling, trace, prompt
|
|
373
|
+
action:
|
|
374
|
+
model: balanced
|
|
375
|
+
maxAgents: 3
|
|
376
|
+
# prompt: .loreli/action.md # optional custom prompt per role
|
|
377
|
+
reviewer:
|
|
378
|
+
model: balanced
|
|
379
|
+
maxAgents: 2
|
|
380
|
+
trace:
|
|
381
|
+
enabled: true
|
|
382
|
+
maxOutputChars: 4000
|
|
383
|
+
risk:
|
|
384
|
+
model: fast
|
|
385
|
+
maxAgents: 3
|
|
386
|
+
skip: false
|
|
387
|
+
trace:
|
|
388
|
+
enabled: true
|
|
389
|
+
maxOutputChars: 2000
|
|
390
|
+
planner:
|
|
391
|
+
model: powerful
|
|
392
|
+
maxAgents: 1
|
|
393
|
+
trace:
|
|
394
|
+
enabled: true
|
|
395
|
+
maxOutputChars: 4000
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
`pr.validation.command` and `pr.selfReview.enabled` harden PR creation quality gates and are enabled by default:
|
|
399
|
+
|
|
400
|
+
- `pr.validation.command` defaults to `npm test`; customize it per repository when needed.
|
|
401
|
+
- `pr.selfReview.enabled` defaults to `true`; set it to `false` only when explicitly opting out.
|
|
402
|
+
|
|
403
|
+
Config values are resolved through four layers (highest priority first):
|
|
404
|
+
|
|
405
|
+
```mermaid
|
|
406
|
+
flowchart LR
|
|
407
|
+
BP["Start Params"] --> YML["loreli.yml"]
|
|
408
|
+
YML --> ENV["Env Vars"]
|
|
409
|
+
ENV --> DEF["Built-in Defaults"]
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
See [packages/config/README.md](packages/config/README.md) for the full schema and API reference.
|
|
413
|
+
|
|
414
|
+
## Branch Isolation
|
|
415
|
+
|
|
416
|
+
Loreli supports redirecting all agent work to a dedicated branch, keeping `main` untouched until a human is ready to promote.
|
|
417
|
+
|
|
418
|
+
```
|
|
419
|
+
main ─────────────────────────────────────── human review ──▶ main
|
|
420
|
+
│ ▲
|
|
421
|
+
└──▶ loreli ──▶ agent PRs merge here ──────────────┘
|
|
422
|
+
│ ▲ ▲
|
|
423
|
+
├── agent-0/issue-1 ───┘ (auto-merge)
|
|
424
|
+
└── agent-1/issue-2 ───┘ (auto-merge)
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Set `merge.base` in `loreli.yml` to enable:
|
|
428
|
+
|
|
429
|
+
```yaml
|
|
430
|
+
merge:
|
|
431
|
+
base: loreli # agents PR against this branch, not main
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
The scaffolding template already defaults to `loreli`. Repositories that omit `merge.base` or explicitly set it to `main` retain the current behavior — agents PR directly against `main`.
|
|
435
|
+
|
|
436
|
+
When enabled, the setting flows through every system boundary: workspace resets branch from `origin/loreli` instead of `origin/main`, action agents open PRs targeting `loreli`, reviewer workspaces sync `loreli` alongside the PR head, and the relay auto-PR path uses the configured base. A single human-created PR from `loreli → main` rolls up all agent work for final review.
|
|
437
|
+
|
|
438
|
+
See [packages/config/README.md](packages/config/README.md#configurable-base-branch) for the full technical details including resolution order and affected code paths.
|
|
439
|
+
|
|
440
|
+
## Custom Prompt Extensions
|
|
441
|
+
|
|
442
|
+
Projects can inject custom instructions into agent prompts by setting `workflows.{role}.prompt` in `loreli.yml`. Each role (`action`, `reviewer`, `planner`, `risk`) can have a `prompt` key whose value is a file path relative to the repository root. Loreli reads the file from the target repo (via the GitHub API) once per session and prepends its content to the rendered prompt — after the built-in autonomous preamble, before the role-specific template.
|
|
443
|
+
|
|
444
|
+
This mechanism addresses a common need: different repositories have different coding standards, architectural constraints, or domain knowledge that agents should follow. Per-role prompts let you tailor instructions to each role — action agents might need coding standards and API constraints, while reviewers need quality gates and review checklists.
|
|
445
|
+
|
|
446
|
+
### Setup
|
|
447
|
+
|
|
448
|
+
Create prompt files in your repository — for example under `.loreli/`:
|
|
449
|
+
|
|
450
|
+
```markdown
|
|
451
|
+
<!-- .loreli/action.md -->
|
|
452
|
+
<project-rules>
|
|
453
|
+
|
|
454
|
+
- This project uses the internal Design System v3 — import components from `@acme/ds3`.
|
|
455
|
+
- All API calls must go through the gateway at `https://api.internal.acme.com`.
|
|
456
|
+
- Never use inline styles; use CSS modules exclusively.
|
|
457
|
+
- Database migrations require a paired rollback script in `db/rollback/`.
|
|
458
|
+
|
|
459
|
+
</project-rules>
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
```markdown
|
|
463
|
+
<!-- .loreli/review.md -->
|
|
464
|
+
<review-standards>
|
|
465
|
+
|
|
466
|
+
- Every PR must have at least 90% test coverage on changed files.
|
|
467
|
+
- Flag any direct database queries — all access must go through the ORM.
|
|
468
|
+
- Reject PRs that introduce new `any` types in TypeScript.
|
|
469
|
+
|
|
470
|
+
</review-standards>
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
Then reference them in `loreli.yml` under `workflows`:
|
|
474
|
+
|
|
475
|
+
```yaml
|
|
476
|
+
workflows:
|
|
477
|
+
action:
|
|
478
|
+
prompt: .loreli/action.md
|
|
479
|
+
reviewer:
|
|
480
|
+
prompt: .loreli/review.md
|
|
481
|
+
planner:
|
|
482
|
+
prompt: .loreli/planner.md
|
|
483
|
+
risk:
|
|
484
|
+
prompt: .loreli/risk.md # optional — omit roles that don't need custom prompts
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
After the next `start()`, each agent role receives only its own custom instructions at the top of its prompt, before the role-specific template content. Roles without a configured prompt file are unaffected.
|
|
488
|
+
|
|
489
|
+
### How It Works
|
|
490
|
+
|
|
491
|
+
The custom prompt flows through the same rendering pipeline as the autonomous preamble — `Workflow.render()` and `Workflow.renderFrom()` resolve `workflows.{role}.prompt` from config and prepend the content automatically. The injection order is:
|
|
492
|
+
|
|
493
|
+
1. **Autonomous preamble** — built-in headless operation directives (always present)
|
|
494
|
+
2. **Custom prompt** — role-specific project instructions from `workflows.{role}.prompt` (when configured)
|
|
495
|
+
3. **Role template** — the action/planner/reviewer prompt
|
|
496
|
+
|
|
497
|
+
The file is read once from GitHub when the first prompt for that role is rendered and cached for the remainder of the session. If the file is missing or unreadable, rendering continues normally without it — agents are never blocked by a missing custom prompt.
|
|
498
|
+
|
|
499
|
+
### Guidelines
|
|
500
|
+
|
|
501
|
+
The custom prompt is static text — it is not processed through Mustache templates. Tailor each role's prompt to its responsibilities:
|
|
502
|
+
|
|
503
|
+
- **Action prompts**: coding standards, architecture constraints, API endpoints, forbidden patterns, required tooling, domain terminology
|
|
504
|
+
- **Reviewer prompts**: quality gates, review checklists, coverage requirements, security policies, patterns to flag
|
|
505
|
+
- **Planner prompts**: planning methodology, decomposition guidelines, estimation rules, scope constraints
|
|
506
|
+
- **Risk prompts**: threat models, compliance requirements, security baselines, risk tolerance thresholds
|
|
507
|
+
|
|
508
|
+
Wrap content in descriptive XML tags (e.g. `<project-rules>`, `<review-standards>`) so agents can clearly identify the boundary between project instructions and role instructions.
|
|
509
|
+
|
|
510
|
+
## Human In The Loop (HITL)
|
|
511
|
+
|
|
512
|
+
When `reviewers` is non-empty or `merge.hitl` is `true`, Loreli activates Human In The Loop (HITL). Loreli intentionally diverges from the [Harness Engineering article](https://openai.com/index/harness-engineering/)'s non-blocking philosophy: HITL provides a configurable safety net for teams that want human approval before merge, while `hitl: false` enables fully autonomous agent merges when confidence is high.
|
|
513
|
+
|
|
514
|
+
```mermaid
|
|
515
|
+
sequenceDiagram
|
|
516
|
+
participant Agents as Agent Team
|
|
517
|
+
participant GH as GitHub PR
|
|
518
|
+
participant Orch as Orchestrator
|
|
519
|
+
participant Human as Human Reviewer
|
|
520
|
+
|
|
521
|
+
Agents->>GH: Open PR + review + approve
|
|
522
|
+
Orch->>GH: Request review + assign humans
|
|
523
|
+
Orch->>GH: Post summary @tagging reviewers
|
|
524
|
+
Orch->>Orch: Kill agents
|
|
525
|
+
Note over GH: awaiting_hitl
|
|
526
|
+
Human->>GH: Merge OR comment
|
|
527
|
+
alt human merges
|
|
528
|
+
Note over GH: Done
|
|
529
|
+
else human comments
|
|
530
|
+
Orch->>Orch: Spawn fresh agent
|
|
531
|
+
Agents->>GH: Address feedback
|
|
532
|
+
Orch->>GH: Re-request review
|
|
533
|
+
end
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
## Yin/Yang Review
|
|
537
|
+
|
|
538
|
+
Loreli pairs agents from opposing AI providers for adversarial review. OpenAI agents create work that Anthropic agents review, and vice versa. Themed identities make agent teams visually distinct — each theme has a yang faction (mapped to OpenAI) and a yin faction (mapped to Anthropic).
|
|
539
|
+
|
|
540
|
+
| Theme | Yang (OpenAI) | Yin (Anthropic) | Council |
|
|
541
|
+
|-------|---------------|-----------------|---------|
|
|
542
|
+
| Transformers | Autobots | Decepticons | The Allspark |
|
|
543
|
+
| Pokemon | Fire types | Water types | Professor Oak |
|
|
544
|
+
| Marvel | Avengers | X-Men | S.H.I.E.L.D. |
|
|
545
|
+
| Digimon | Vaccine | Virus | Yggdrasil |
|
|
546
|
+
| Star Wars | Jedi | Sith | The Force |
|
|
547
|
+
| Lord of the Rings | Fellowship | Mordor | The Valar |
|
|
548
|
+
| Dragon Ball | Z Fighters | Villains | Grand Zeno |
|
|
549
|
+
| Avatar | Benders | Fire Nation | Raava |
|
|
550
|
+
| Zelda | Hyrule | Shadow | Hylia |
|
|
551
|
+
|
|
552
|
+
Each theme also has a **council** — a central authority that transcends the yang/yin split. The council identity is used for orchestrator-level actions like proof-of-life requests, where messages should come from the system itself rather than a faction.
|
|
553
|
+
|
|
554
|
+
When `theme` is set to a list of themes in `loreli.yml`, Loreli picks one at random for each work item. All agents within that work item (action + reviewer, planner + reviewer) share the same theme so antagonist pairs remain coherent -- Autobots always face Decepticons, never Team Rocket.
|
|
555
|
+
|
|
556
|
+
When cross-provider review isn't possible, the system falls back to single-side fresh-instance review while keeping action and reviewer identities distinct.
|
|
557
|
+
|
|
558
|
+
## Distributed Coordination
|
|
559
|
+
|
|
560
|
+
Multiple Loreli MCP instances can run against the same repository simultaneously. GitHub is the single source of truth — there are no local coordination files or locks. The proof-of-life system prevents duplicate work when an orchestrator restarts or crashes.
|
|
561
|
+
|
|
562
|
+
### The Problem
|
|
563
|
+
|
|
564
|
+
When orchestrator A crashes while its agents hold claims on issues or PRs, orchestrator B (started later or running in parallel) sees those claims but has no local record of the agents. Without coordination, B would either:
|
|
565
|
+
- **Evict immediately** — releasing claims and causing duplicate work if A's agents are still alive
|
|
566
|
+
- **Wait forever** — never reclaiming work from genuinely dead agents
|
|
567
|
+
|
|
568
|
+
### Proof-of-Life Protocol
|
|
569
|
+
|
|
570
|
+
Loreli uses an on-demand request-response protocol via GitHub comments to verify agent liveness across orchestrators. No constant heartbeat — requests are only posted when a foreign claim is detected.
|
|
571
|
+
|
|
572
|
+
```mermaid
|
|
573
|
+
sequenceDiagram
|
|
574
|
+
participant B as Orchestrator B
|
|
575
|
+
participant GH as GitHub
|
|
576
|
+
participant A as Orchestrator A
|
|
577
|
+
|
|
578
|
+
B->>GH: Detects claim by agent unknown to B
|
|
579
|
+
Note over B: Check recent GitHub activity first
|
|
580
|
+
alt recent activity found
|
|
581
|
+
Note over B: Skip — agent is probably alive
|
|
582
|
+
else no recent activity
|
|
583
|
+
B->>GH: Post themed proof-of-life request (council identity)
|
|
584
|
+
Note over A: Reactor tick detects request
|
|
585
|
+
A->>A: Run health(agent) check
|
|
586
|
+
A->>GH: Post themed alive response (agent identity)
|
|
587
|
+
B->>GH: Read alive response on next tick
|
|
588
|
+
alt alive response found
|
|
589
|
+
Note over B: Skip — agent confirmed alive
|
|
590
|
+
else no response within timeout
|
|
591
|
+
B->>GH: Release claim, dispatch new agent
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
Both request and response comments are **themed**. Requests use the theme's **council** identity — a central authority that transcends the yang/yin faction split (e.g. "The Allspark" for Transformers, "Professor Oak" for Pokemon). Responses use the target agent's own faction identity. Machine-readable markers are embedded alongside the visible themed text.
|
|
597
|
+
|
|
598
|
+
### Four-Gate Eviction
|
|
599
|
+
|
|
600
|
+
Before evicting a foreign agent's claim, the detecting workflow runs four checks in order:
|
|
601
|
+
|
|
602
|
+
1. **Local removal check** — Was this agent killed by our own stall detection? If yes, evict immediately (no network call needed).
|
|
603
|
+
2. **Own request check** — Is there a pending proof-of-life request from **this** orchestrator (matched by `sessionId`)? If yes, check for a response or wait for the timeout.
|
|
604
|
+
3. **Any request check** — Is there a request from a **different** orchestrator? If it has a valid response, the agent is alive. If it expired, post a fresh request from this orchestrator instead of evicting — the agent deserves a chance to respond to the new owner.
|
|
605
|
+
4. **Recent activity check** — Has anyone commented within the `proofOfLife.timeout` window? If yes, the agent is likely alive.
|
|
606
|
+
5. **Post request** — No activity and no pending request → post a new proof-of-life request and wait until the next reactor tick.
|
|
607
|
+
|
|
608
|
+
### Release Markers
|
|
609
|
+
|
|
610
|
+
Every eviction posts a `review-release` (or `release` for action claims) marker comment. This is critical for preventing the **hydrate-evict loop**: without it, `hydrate()` would re-discover the old claim comment on the next tick, re-add it to the in-memory map, and trigger eviction again — forever. The `hydrate()` step checks for release markers after claims and skips them.
|
|
611
|
+
|
|
612
|
+
### Health Check
|
|
613
|
+
|
|
614
|
+
The `health()` method on the orchestrator evaluates multiple signals when responding to a proof-of-life request:
|
|
615
|
+
|
|
616
|
+
| Signal | Check | Result |
|
|
617
|
+
|--------|-------|--------|
|
|
618
|
+
| **Process** | Is the tmux pane alive? | `unhealthy` if dead |
|
|
619
|
+
| **State** | Is the agent dormant? | `unhealthy` if dormant |
|
|
620
|
+
| **Activity** | Last orchestrator interaction within stall timeout? | `unhealthy` if stale |
|
|
621
|
+
| **Output** | Captured terminal output length | Included for diagnostics |
|
|
622
|
+
|
|
623
|
+
### Configuration
|
|
624
|
+
|
|
625
|
+
| Key | Default | Description |
|
|
626
|
+
|-----|---------|-------------|
|
|
627
|
+
| `proofOfLife.timeout` | `5m` | How long to wait for an alive response before evicting |
|
|
628
|
+
|
|
629
|
+
```yaml
|
|
630
|
+
# loreli.yml
|
|
631
|
+
proofOfLife:
|
|
632
|
+
timeout: 5m # time window for proof-of-life responses
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
## Label Tracking
|
|
636
|
+
|
|
637
|
+
Every agent-created artifact (issue, PR, or discussion) gets labeled for tracking and attribution:
|
|
638
|
+
|
|
639
|
+
| Label | Example | Description |
|
|
640
|
+
|-------|---------|-------------|
|
|
641
|
+
| `loreli` | `loreli` | Marks all Loreli-managed items |
|
|
642
|
+
| `loreli:<provider>` | `loreli:anthropic` | AI provider that created the artifact |
|
|
643
|
+
| `model:<name>` | `model:claude-sonnet-4` | Human-readable model name |
|
|
644
|
+
| `loreli:<role>` | `loreli:action` | Agent role |
|
|
645
|
+
| `loreli:approved` | `loreli:approved` | Plan or PR approved |
|
|
646
|
+
| `loreli:changes-requested` | `loreli:changes-requested` | Revision required |
|
|
647
|
+
|
|
648
|
+
Start creates base labels (`loreli`, `loreli:planner`, `loreli:action`, `loreli:reviewer`, etc.), and `add_agent` ensures model-specific labels exist. Set `labels.track: false` in `loreli.yml` to disable label tracking. Use `labels.extra` to add custom labels to all agent artifacts.
|
|
649
|
+
|
|
650
|
+
## Machine-Readable Markers
|
|
651
|
+
|
|
652
|
+
Loreli uses HTML comment markers (`<!-- loreli:TYPE key="value" -->`) to embed machine-readable metadata in GitHub content without affecting the visible presentation. Marker types include `claim`, `signoff`, `release`, `gate`, `agent`, `signature`, `review-event`, `feedback`, `promotion`, and `trace`/`trace-end`. This decouples workflow state from human-visible text — markers survive edits to the visible body and are used by the orchestrator to detect claims, sign-offs, and HITL transitions. The `trace` paired markers wrap collapsible agent reasoning and output blocks in PR bodies — visible to humans on GitHub but automatically stripped before reaching reviewer prompts or the `read` tool. See [packages/marker/README.md](packages/marker/README.md) for the full API.
|
|
653
|
+
|
|
654
|
+
## Knowledge Capture
|
|
655
|
+
|
|
656
|
+
Loreli compounds lessons across review cycles. When a reviewer requests changes — on a PR or a plan discussion — the feedback is classified into a category (`naming`, `architecture`, `testing`, `documentation`, `performance`, `security`) and tagged with a `loreli:feedback` marker. The `source` attribute distinguishes PR reviews (`source="pr"`) from plan verdicts (`source="plan"`).
|
|
657
|
+
|
|
658
|
+
When a category accumulates enough markers across PRs and discussions (configurable via `feedback.threshold`, default 5), the `knowledge` reactor proposes a promotion via a GitHub Discussion with a structured template. The template pre-selects a promotion target based on feedback source — discussion-dominated patterns suggest the planner prompt, PR-dominated patterns suggest the action prompt, and mixed patterns suggest AGENTS.md. Humans make the final selection from all available targets (`AGENTS.md`, `.loreli/planner.md`, `.loreli/review.md`, `.loreli/action.md`, `.loreli/risk.md`), then close the discussion to trigger an action issue that an agent implements.
|
|
659
|
+
|
|
660
|
+
This creates a ratchet effect — each review cycle makes all future agent work better. See [packages/knowledge/README.md](packages/knowledge/README.md) for the full API and [PDR-007](docs/pdr/PDR-007-knowledge-capture.md) for the design rationale.
|
|
661
|
+
|
|
662
|
+
## MCP Tools
|
|
663
|
+
|
|
664
|
+
### Orchestration Tools (called by the user or parent agent)
|
|
665
|
+
|
|
666
|
+
| Tool | Description |
|
|
667
|
+
|------|-------------|
|
|
668
|
+
| `start` | Initialize repo — discover/scaffold files, MCP configs, labels, load config, create session |
|
|
669
|
+
| `environment` | Report tmux, backends, providers, review strategy |
|
|
670
|
+
| `add_agent` | Spawn agent with identity, backend, model, role |
|
|
671
|
+
| `agents` | Query agent team — `list` all agents or `check` health of one/all |
|
|
672
|
+
| `start_planning` | Activate planners with an objective, start reactor |
|
|
673
|
+
| `start_work` | Begin claim-work-review cycle |
|
|
674
|
+
| `team_status` | Dashboard of issues, PRs, agents, review loops, rate limits |
|
|
675
|
+
| `hitl` | Hand PR to human reviewers (Human In The Loop), shut down agents |
|
|
676
|
+
| `watch` | Check HITL PR for human feedback |
|
|
677
|
+
| `stop` | Stop an agent — `shutdown` (graceful) or `kill` (forced) |
|
|
678
|
+
|
|
679
|
+
### Agent Tools (called by spawned agents via their MCP connection)
|
|
680
|
+
|
|
681
|
+
These tools are called by agents running in tmux panes via their `.mcp.json` connection back to Loreli. All context (repo, identity, role, task) is resolved from the agent's session — zero identifier parameters, eliminating hallucination vectors.
|
|
682
|
+
|
|
683
|
+
| Tool | Description |
|
|
684
|
+
|------|-------------|
|
|
685
|
+
| `plan` | Manage plan discussions — `create`, `revise`, `verdict`, `escalate` |
|
|
686
|
+
| `pr` | Manage pull requests — `create` (with auto-commit/push + trace), `review` (with trace). Agents include `reasoning` to document their approach; terminal output and token usage are captured automatically. |
|
|
687
|
+
| `comment` | Post comments on current work item, or `claim` an issue |
|
|
688
|
+
| `read` | Read any issue, PR, or discussion by number with optional comments |
|
|
689
|
+
| `context` | Resolve code context — `blame` a line to its PR/issue/discussion chain, `history` of a file, `search` across artifacts, `patterns` for recurring review feedback |
|
|
690
|
+
|
|
691
|
+
## Environment Variables
|
|
692
|
+
|
|
693
|
+
Copy `.env.example` to `.env` and fill in the values. Variables set in the shell always take precedence.
|
|
694
|
+
|
|
695
|
+
| Variable | Required | Description |
|
|
696
|
+
|----------|----------|-------------|
|
|
697
|
+
| `GITHUB_TOKEN` | Yes | GitHub personal access token with `repo` scope |
|
|
698
|
+
| `LORELI_HOME` | No | Override `~/.loreli/` session storage path |
|
|
699
|
+
| `LORELI_LOG_LEVEL` | No | Log level: `error`, `warn`, `info` (default), `debug` |
|
|
700
|
+
| `LORELI_TEST_REPO` | No | GitHub repo for integration tests (`owner/name` format) |
|
|
701
|
+
| `LORELI_SESSION` | No | Set automatically for agent MCP servers — session ID |
|
|
702
|
+
| `LORELI_AGENT` | No | Set automatically for agent MCP servers — agent name |
|
|
703
|
+
| `LORELI_REPO` | No | Set automatically for agent MCP servers — target repo |
|
|
704
|
+
|
|
705
|
+
See [packages/config/README.md](packages/config/README.md) for the full env-to-config mapping and `loadEnv()` API.
|
|
706
|
+
|
|
707
|
+
## Project Governance
|
|
708
|
+
|
|
709
|
+
- Contributing guide: [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
710
|
+
- Code of Conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
|
711
|
+
- Security policy: [SECURITY.md](SECURITY.md)
|
|
712
|
+
- Changelog: [CHANGELOG.md](CHANGELOG.md)
|
|
100
713
|
|
|
101
714
|
## License
|
|
102
715
|
|