loreli 0.0.0 → 1.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.
Files changed (88) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +670 -97
  3. package/bin/loreli.js +89 -0
  4. package/package.json +74 -14
  5. package/packages/README.md +101 -0
  6. package/packages/action/README.md +98 -0
  7. package/packages/action/src/index.js +656 -0
  8. package/packages/agent/README.md +517 -0
  9. package/packages/agent/src/backends/claude.js +287 -0
  10. package/packages/agent/src/backends/codex.js +278 -0
  11. package/packages/agent/src/backends/cursor.js +294 -0
  12. package/packages/agent/src/backends/index.js +329 -0
  13. package/packages/agent/src/base.js +138 -0
  14. package/packages/agent/src/cli.js +198 -0
  15. package/packages/agent/src/factory.js +119 -0
  16. package/packages/agent/src/index.js +12 -0
  17. package/packages/agent/src/models.js +141 -0
  18. package/packages/agent/src/output.js +62 -0
  19. package/packages/agent/src/session.js +162 -0
  20. package/packages/agent/src/trace.js +186 -0
  21. package/packages/config/README.md +833 -0
  22. package/packages/config/src/defaults.js +134 -0
  23. package/packages/config/src/index.js +192 -0
  24. package/packages/config/src/schema.js +273 -0
  25. package/packages/config/src/validate.js +160 -0
  26. package/packages/context/README.md +165 -0
  27. package/packages/context/src/index.js +198 -0
  28. package/packages/hub/README.md +338 -0
  29. package/packages/hub/src/base.js +154 -0
  30. package/packages/hub/src/github.js +1558 -0
  31. package/packages/hub/src/index.js +79 -0
  32. package/packages/hub/src/labels.js +48 -0
  33. package/packages/identity/README.md +288 -0
  34. package/packages/identity/src/index.js +620 -0
  35. package/packages/identity/src/themes/avatar.js +217 -0
  36. package/packages/identity/src/themes/digimon.js +217 -0
  37. package/packages/identity/src/themes/dragonball.js +217 -0
  38. package/packages/identity/src/themes/lotr.js +217 -0
  39. package/packages/identity/src/themes/marvel.js +217 -0
  40. package/packages/identity/src/themes/pokemon.js +217 -0
  41. package/packages/identity/src/themes/starwars.js +217 -0
  42. package/packages/identity/src/themes/transformers.js +217 -0
  43. package/packages/identity/src/themes/zelda.js +217 -0
  44. package/packages/knowledge/README.md +237 -0
  45. package/packages/knowledge/src/index.js +412 -0
  46. package/packages/log/README.md +93 -0
  47. package/packages/log/src/index.js +252 -0
  48. package/packages/marker/README.md +200 -0
  49. package/packages/marker/src/index.js +184 -0
  50. package/packages/mcp/README.md +279 -0
  51. package/packages/mcp/instructions.md +121 -0
  52. package/packages/mcp/scaffolding/.agents/skills/loreli-context/SKILL.md +89 -0
  53. package/packages/mcp/scaffolding/ISSUE_TEMPLATE/config.yml +2 -0
  54. package/packages/mcp/scaffolding/ISSUE_TEMPLATE/loreli.yml +83 -0
  55. package/packages/mcp/scaffolding/loreli.yml +453 -0
  56. package/packages/mcp/scaffolding/mcp-configs/.codex/config.toml +3 -0
  57. package/packages/mcp/scaffolding/mcp-configs/.cursor/mcp.json +11 -0
  58. package/packages/mcp/scaffolding/mcp-configs/.mcp.json +11 -0
  59. package/packages/mcp/scaffolding/pull-request.md +23 -0
  60. package/packages/mcp/src/index.js +571 -0
  61. package/packages/mcp/src/tools/agents.js +429 -0
  62. package/packages/mcp/src/tools/context.js +199 -0
  63. package/packages/mcp/src/tools/github.js +1199 -0
  64. package/packages/mcp/src/tools/hitl.js +149 -0
  65. package/packages/mcp/src/tools/index.js +17 -0
  66. package/packages/mcp/src/tools/start.js +835 -0
  67. package/packages/mcp/src/tools/status.js +146 -0
  68. package/packages/mcp/src/tools/work.js +124 -0
  69. package/packages/orchestrator/README.md +192 -0
  70. package/packages/orchestrator/src/index.js +1226 -0
  71. package/packages/planner/README.md +168 -0
  72. package/packages/planner/src/index.js +1166 -0
  73. package/packages/review/README.md +129 -0
  74. package/packages/review/src/index.js +1283 -0
  75. package/packages/risk/README.md +119 -0
  76. package/packages/risk/src/index.js +428 -0
  77. package/packages/session/README.md +165 -0
  78. package/packages/session/src/index.js +215 -0
  79. package/packages/test-utils/README.md +96 -0
  80. package/packages/test-utils/src/index.js +354 -0
  81. package/packages/tmux/README.md +261 -0
  82. package/packages/tmux/src/index.js +452 -0
  83. package/packages/workflow/README.md +313 -0
  84. package/packages/workflow/src/index.js +481 -0
  85. package/packages/workflow/src/proof-of-life.js +74 -0
  86. package/packages/workspace/README.md +143 -0
  87. package/packages/workspace/src/index.js +1076 -0
  88. package/index.js +0 -8
package/README.md CHANGED
@@ -1,102 +1,675 @@
1
1
  # Loreli
2
2
 
3
- Loreli is an agentic system that uses the GitHub patterns we're familiar with for orchestration. Issues becomes actions for agents. Pull Requests are review tasks. Discussions are where plans are discussed and then raised as issues on approval. The system uses an antagonist style where OpenAI will always be checked by Antrophic, ensuring you get input from both models.
4
-
5
- ## Status
6
-
7
- Active development. Expect breaking changes until the first stable release.
8
-
9
- ## Goals
10
-
11
- - Use GitHub issues as the system's action queue
12
- - Use pull requests as review tasks with explicit acceptance criteria
13
- - Use discussions as planning and approval forums
14
- - Maintain an antagonist style: every decision is checked by an opposing model
15
- - Provide an MCP server to expose orchestration primitives to agents and tools
16
-
17
- ### Architecture Overview
18
-
19
- - GitHub Repo (source of truth)
20
- - Issues: actionable work items, one per task
21
- - Discussions: planning, debates, and approval
22
- - Pull Requests: review and acceptance gates
23
- - MCP Server (orchestrator)
24
- - Watches GitHub events (issues, PRs, discussions)
25
- - Assigns tasks to agent runners
26
- - Stores run state and artifacts
27
- - Agent Runners
28
- - Worker processes that perform tasks (coding, analysis, documentation)
29
- - Must use the MCP server for all GitHub interactions
30
- - Antagonist Pairing
31
- - For every primary agent action, a secondary agent provides critique
32
- - MCP server aggregates both and posts back to GitHub
33
-
34
- ### Workflow (Happy Path)
35
-
36
- 1. Planning happens in a GitHub Discussion.
37
- 2. When a plan is approved, each action item becomes an Issue.
38
- 3. The MCP server detects new issues and assigns them to agents.
39
- 4. The primary agent produces a proposal; the antagonist critiques it.
40
- 5. The MCP server posts both to the Issue and optionally creates a PR.
41
- 6. The PR is the review task; it links to the Issue and Discussion.
42
- 7. Reviewers approve or request changes; MCP server updates status.
43
-
44
- ### Core Components
45
-
46
- #### MCP Server
47
-
48
- Responsibilities:
49
- - Subscribe to GitHub webhooks
50
- - Maintain a task queue keyed by Issue/PR IDs
51
- - Provide MCP methods for:
52
- - `list_issues`, `get_issue`, `comment_issue`
53
- - `create_pr`, `update_pr`, `request_review`
54
- - `list_discussions`, `create_discussion`, `comment_discussion`
55
- - `assign_agent`, `store_artifact`, `fetch_artifact`
56
- - Enforce antagonist pairing
57
-
58
- #### Issue Model
59
-
60
- Each Issue should have:
61
- - Title: actionable, specific
62
- - Labels: `type/*`, `priority/*`, `status/*`
63
- - Checklist: acceptance criteria
64
- - Links: relevant Discussion and related PR
65
-
66
- #### PR Model
67
-
68
- Each PR should:
69
- - Reference the Issue it resolves
70
- - Include a summary, risks, and test plan
71
- - Include a section for antagonist critique
72
-
73
- ### Antagonist Style
74
-
75
- Every action must be checked by an opposing model:
76
- - Primary agent: propose solution and implementation
77
- - Antagonist agent: identify risks, missing tests, alternative approaches
78
- - MCP server posts both as a paired response
79
- - Issues and PRs are not marked complete without antagonist feedback
80
-
81
- ### Data and State
82
-
83
- - GitHub is the canonical record of decisions and status
84
- - MCP server stores ephemeral state (task queue, agent assignments)
85
- - Artifacts (logs, intermediate outputs) stored in a simple object store
86
-
87
- ### Security and Access
88
-
89
- - MCP server uses GitHub App authentication
90
- - Principle of least privilege: read/write issues, PRs, discussions only
91
- - All agent actions are logged and attributed in GitHub
92
-
93
- ### Initial Milestones
94
-
95
- 1. MCP server skeleton with GitHub webhook handling
96
- 2. Basic issue-to-agent assignment
97
- 3. Antagonist pairing and GitHub comments
98
- 4. PR creation and review loop
99
- 5. Stable operational docs and onboarding
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
+
56
+ <details>
57
+ <summary>Using a fine-grained token instead</summary>
58
+
59
+ 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:
60
+
61
+ - **Contents** reading/writing repo files
62
+ - **Issues** creating/managing issues and comments
63
+ - **Pull requests** — creating PRs, requesting reviews, merging
64
+ - **Discussions** creating plan discussions and comments
65
+ - **Metadata** — read-only (required by GitHub for all fine-grained tokens)
66
+
67
+ Set the **Resource owner** and **Repository access** to match the repos you plan to orchestrate.
68
+ </details>
69
+
70
+ ### 3. Install Loreli
71
+
72
+ 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.
73
+
74
+ ```bash
75
+ npm install -g loreli
76
+ ```
77
+
78
+ Hold off on running `loreli` commands until you've completed Step 4, because the CLI relies on the MCP server entry being configured.
79
+
80
+ ### 4. Configure Your MCP Client
81
+
82
+ 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.
83
+
84
+ **Cursor / VS Code** — open **Settings** > search **MCP** > **Edit in settings.json**, or add directly to your user-level `~/.cursor/mcp.json`:
85
+
86
+ ```json
87
+ {
88
+ "mcpServers": {
89
+ "loreli": {
90
+ "command": "npx",
91
+ "args": ["loreli", "mcp"],
92
+ "env": {
93
+ "GITHUB_TOKEN": "ghp_your_token_here"
94
+ }
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ **Claude Code (CLI)** — add to your user-level config at `~/.claude/.mcp.json`:
101
+
102
+ ```json
103
+ {
104
+ "mcpServers": {
105
+ "loreli": {
106
+ "command": "npx",
107
+ "args": ["loreli", "mcp"],
108
+ "env": {
109
+ "GITHUB_TOKEN": "ghp_your_token_here"
110
+ }
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ The `env` block keeps the token scoped to Loreli's process. 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.
117
+
118
+ <details>
119
+ <summary>Claude Desktop</summary>
120
+
121
+ Add to your Claude Desktop config file:
122
+
123
+ - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
124
+
125
+ ```json
126
+ {
127
+ "mcpServers": {
128
+ "loreli": {
129
+ "command": "npx",
130
+ "args": ["loreli", "mcp"],
131
+ "env": {
132
+ "GITHUB_TOKEN": "ghp_your_token_here"
133
+ }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+ </details>
139
+
140
+ <details>
141
+ <summary>Codex CLI</summary>
142
+
143
+ Add to `~/.codex/config.toml` (user-level):
144
+
145
+ ```toml
146
+ [mcp_servers.loreli]
147
+ command = "npx"
148
+ args = ["loreli", "mcp"]
149
+ ```
150
+
151
+ Codex reads `GITHUB_TOKEN` from the shell environment. Set it in your shell profile before running `codex`.
152
+ </details>
153
+
154
+ 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.
155
+
156
+ ```bash
157
+ loreli --version
158
+ loreli tools list # should print all available MCP tools
159
+ ```
160
+
161
+ ### 5. Prepare Your Repository
162
+
163
+ 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.
164
+
165
+ **Step 1: Enable GitHub Discussions**
166
+
167
+ 1. Go to your repository on GitHub
168
+ 2. Navigate to **Settings** > **General**
169
+ 3. Scroll down to the **Features** section
170
+ 4. Check the **Discussions** checkbox
171
+
172
+ **Step 2: Create the "Loreli" discussion category**
173
+
174
+ 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.
175
+
176
+ 1. Go to your repository's **Discussions** tab
177
+ 2. Click the pencil icon next to **Categories** in the left sidebar
178
+ 3. Click **New category**
179
+ 4. Fill in the form:
180
+ - **Category name**: `Loreli` (exact spelling, case-sensitive)
181
+ - **Description**: `Loreli agent orchestration plans`
182
+ - **Discussion Format**: Open-ended discussion
183
+ 5. Click **Create**
184
+
185
+ **Step 3: Start the repository**
186
+
187
+ With your MCP client connected, call the `start` tool:
188
+
189
+ ```
190
+ start({ repo: "owner/repo-name" })
191
+ ```
192
+
193
+ Or from the CLI:
194
+
195
+ ```bash
196
+ loreli tools start --repo owner/repo-name
197
+ ```
198
+
199
+ 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:
200
+
201
+ | Action | Details |
202
+ |--------|---------|
203
+ | **Scaffolds templates** | PR template, issue templates, `loreli.yml` config |
204
+ | **Configures MCP** | Adds loreli server entry to `.mcp.json`, `.cursor/mcp.json`, `.codex/config.toml` |
205
+ | **Creates labels** | `loreli`, `loreli:planner`, `loreli:action`, `loreli:reviewer`, `loreli:approved`, `loreli:changes-requested`, plus per-provider labels |
206
+ | **Adds dependency** | Ensures `loreli` is in `devDependencies` of `package.json` |
207
+ | **Updates .gitignore** | Adds rules for `.loreli/`, `.claude/`, `.cursor/hooks.json` |
208
+ | **Starts reactor** | Begins the orchestration loop that watches for work |
209
+
210
+ After start, you'll see a summary of the session, detected backends, review strategy, and any files that were scaffolded.
211
+
212
+ ### 6. Your First Run
213
+
214
+ With everything set up, here's the quickest path to seeing Loreli in action:
215
+
216
+ **Create a labeled issue** on your repository with the `loreli` label. The issue body should describe a task — for example:
217
+
218
+ > **Title**: Add a hello world endpoint
219
+ >
220
+ > **Body**: Create a simple `/hello` endpoint that returns `{ "message": "Hello, world!" }`. Add a basic test.
221
+ >
222
+ > **Label**: `loreli`
223
+
224
+ **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:
225
+
226
+ ```
227
+ team_status()
228
+ ```
229
+
230
+ 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).
231
+
232
+ 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.
233
+
234
+ ## Package and Development Docs
235
+
236
+ This README is intentionally focused on operating Loreli as a consumer.
237
+
238
+ For internal architecture, subpackage import docs (`loreli/*`), and contributor/development workflows, see [`packages/README.md`](packages/README.md).
239
+ For topology-aware end-to-end testing (`pnpm e2e`, `pnpm e2e:single`, `pnpm e2e:multi`), see [`e2e/README.md`](e2e/README.md).
240
+
241
+ ## Agent Workflow
242
+
243
+ 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.
244
+
245
+ ```mermaid
246
+ sequenceDiagram
247
+ participant User as User / Parent Agent
248
+ participant L as Loreli MCP
249
+ participant Orch as Orchestrator
250
+ participant A as Action Agent
251
+ participant R as Review Agent
252
+ participant GH as GitHub
253
+
254
+ User->>L: start(repo)
255
+ L->>GH: discover + scaffold
256
+ Note over Orch: Reactor starts (60s tick)
257
+ User->>GH: Create issue with loreli label
258
+ Note over Orch: Tick detects unclaimed issue
259
+ Orch->>A: Auto-spawn action agent
260
+ A->>GH: Claim issue + create PR
261
+ Orch->>R: Auto-spawn reviewer (opposing side when available)
262
+ R->>GH: Review PR (adversarial)
263
+ A->>GH: Address feedback
264
+ R->>GH: Approve + sign off
265
+ A->>GH: Sign off
266
+ alt auto-merge
267
+ Orch->>GH: Merge PR
268
+ else HITL
269
+ L->>GH: Request human review
270
+ Orch->>Orch: Kill agents
271
+ end
272
+ Note over Orch: Reap idle agents
273
+ Note over Orch: Next tick — repeat
274
+ ```
275
+
276
+ 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.
277
+ 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.
278
+ 3. **Action** — Action agents claim issues (first-comment-wins), create git worktree branches, implement work, and open PRs.
279
+ 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.
280
+ 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.
281
+ 6. **Merge** — Approval from an eligible reviewer triggers auto-merge, or human merges manually.
282
+ 7. **Reap** — When no open issues or PRs remain, idle agents are killed. The cycle repeats on the next tick if new work arrives.
283
+
284
+ **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.
285
+
286
+ ## Agent Death Snapshots
287
+
288
+ 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:
289
+
290
+ ```
291
+ ~/.loreli/sessions/<sessionId>/logs/
292
+ optimus-0.death.log
293
+ megatron-0.death.log
294
+ ```
295
+
296
+ 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`).
297
+
298
+ Death snapshots are cleaned up by `Storage.prune()` alongside other session data when the session expires (default: 12 hours, configurable via `cleanup.retention`).
299
+
300
+ ## Agent Backends
301
+
302
+ Loreli supports multiple agent backends. The `BackendRegistry` auto-discovers which are available at startup.
303
+
304
+ | Backend | CLI Binary | Provider | Description |
305
+ |---------|-----------|----------|-------------|
306
+ | Claude | `claude` | Anthropic | Stays running in tmux, receives messages |
307
+ | Cursor | `cursor-agent` | Multi-provider | Multi-provider via Cursor's model routing |
308
+ | Codex | `codex` | OpenAI | Interactive CLI agent (--full-auto, --no-alt-screen, file-based prompts) |
309
+
310
+ Loreli derives review strategy from detected side capability at runtime:
311
+
312
+ - **Dual-side** (yin + yang detected): cross-provider review and merge gating.
313
+ - **Single-side** (only yin or only yang detected): fresh-instance same-provider review with distinct identities.
314
+
315
+ ## Configuration
316
+
317
+ Each target repository can have a `loreli.yml` in its root. If absent, start scaffolds a default one with all options documented.
318
+
319
+ ```yaml
320
+ # loreli.yml — key settings
321
+ theme: transformers # string or list of themes (randomized per work item)
322
+ # theme: # use a list to randomize:
323
+ # - transformers
324
+ # - pokemon
325
+ # - marvel
326
+ reviewers: [] # GitHub usernames; empty = auto-merge
327
+ merge:
328
+ method: squash # squash | merge | rebase
329
+ hitl: false # false = auto-merge, true = human reviewers
330
+ base: loreli # agents PR against this branch, not main
331
+ pr:
332
+ validation:
333
+ command: npm test # default pre-PR command; blocks pr/create on failure
334
+ selfReview:
335
+ enabled: true # default: pr/create requires preview + confirm=true
336
+ model: balanced # fast | balanced | powerful
337
+ labels:
338
+ track: true # enable provider/model label tracking
339
+ extra: [] # additional labels applied to all loreli items
340
+ timeouts:
341
+ stall: "10m" # human-readable before agent is considered stalled
342
+ shutdown: "1m" # graceful shutdown before kill
343
+ poll: "2s" # orchestrator poll interval
344
+ watch:
345
+ interval: "60s" # reactor tick interval
346
+ maxRounds: 7 # max review rounds before escalation
347
+ trace:
348
+ enabled: true # include agent trace blocks in PR bodies/reviews
349
+ includeOutput: true # include captured terminal output in trace
350
+ maxOutputChars: 8000 # truncate output beyond this limit
351
+ agents:
352
+ disallowedTools: # CLI tools denied in agent workspaces
353
+ - gh
354
+ - curl
355
+ prompts:
356
+ action: .loreli/action.md # custom prompt for action agents (relative to repo root)
357
+ reviewer: .loreli/review.md # custom prompt for reviewer agents
358
+ planner: .loreli/planner.md # custom prompt for planner agents
359
+ risk: .loreli/risk.md # custom prompt for risk agents
360
+ ```
361
+
362
+ `pr.validation.command` and `pr.selfReview.enabled` harden PR creation quality gates and are enabled by default:
363
+
364
+ - `pr.validation.command` defaults to `npm test`; customize it per repository when needed.
365
+ - `pr.selfReview.enabled` defaults to `true`; set it to `false` only when explicitly opting out.
366
+
367
+ Config values are resolved through four layers (highest priority first):
368
+
369
+ ```mermaid
370
+ flowchart LR
371
+ BP["Start Params"] --> YML["loreli.yml"]
372
+ YML --> ENV["Env Vars"]
373
+ ENV --> DEF["Built-in Defaults"]
374
+ ```
375
+
376
+ See [packages/config/README.md](packages/config/README.md) for the full schema and API reference.
377
+
378
+ ## Branch Isolation
379
+
380
+ Loreli supports redirecting all agent work to a dedicated branch, keeping `main` untouched until a human is ready to promote.
381
+
382
+ ```
383
+ main ─────────────────────────────────────── human review ──▶ main
384
+ │ ▲
385
+ └──▶ loreli ──▶ agent PRs merge here ──────────────┘
386
+ │ ▲ ▲
387
+ ├── agent-0/issue-1 ───┘ (auto-merge)
388
+ └── agent-1/issue-2 ───┘ (auto-merge)
389
+ ```
390
+
391
+ Set `merge.base` in `loreli.yml` to enable:
392
+
393
+ ```yaml
394
+ merge:
395
+ base: loreli # agents PR against this branch, not main
396
+ ```
397
+
398
+ 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`.
399
+
400
+ 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.
401
+
402
+ See [packages/config/README.md](packages/config/README.md#configurable-base-branch) for the full technical details including resolution order and affected code paths.
403
+
404
+ ## Custom Prompt Extensions
405
+
406
+ Projects can inject custom instructions into agent prompts by setting `prompts.{role}` in `loreli.yml`. Each key maps to a role (`action`, `reviewer`, `planner`, `risk`) and the 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.
407
+
408
+ 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.
409
+
410
+ ### Setup
411
+
412
+ Create prompt files in your repository — for example under `.loreli/`:
413
+
414
+ ```markdown
415
+ <!-- .loreli/action.md -->
416
+ <project-rules>
417
+
418
+ - This project uses the internal Design System v3 — import components from `@acme/ds3`.
419
+ - All API calls must go through the gateway at `https://api.internal.acme.com`.
420
+ - Never use inline styles; use CSS modules exclusively.
421
+ - Database migrations require a paired rollback script in `db/rollback/`.
422
+
423
+ </project-rules>
424
+ ```
425
+
426
+ ```markdown
427
+ <!-- .loreli/review.md -->
428
+ <review-standards>
429
+
430
+ - Every PR must have at least 90% test coverage on changed files.
431
+ - Flag any direct database queries — all access must go through the ORM.
432
+ - Reject PRs that introduce new `any` types in TypeScript.
433
+
434
+ </review-standards>
435
+ ```
436
+
437
+ Then reference them in `loreli.yml`:
438
+
439
+ ```yaml
440
+ prompts:
441
+ action: .loreli/action.md
442
+ reviewer: .loreli/review.md
443
+ planner: .loreli/planner.md
444
+ risk: .loreli/risk.md # optional — omit roles that don't need custom prompts
445
+ ```
446
+
447
+ 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.
448
+
449
+ ### How It Works
450
+
451
+ The custom prompt flows through the same rendering pipeline as the autonomous preamble — `Workflow.render()` and `Workflow.renderFrom()` resolve `prompts.{role}` from config and prepend the content automatically. The injection order is:
452
+
453
+ 1. **Autonomous preamble** — built-in headless operation directives (always present)
454
+ 2. **Custom prompt** — role-specific project instructions from `prompts.{role}` (when configured)
455
+ 3. **Role template** — the action/planner/reviewer prompt
456
+
457
+ 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.
458
+
459
+ ### Guidelines
460
+
461
+ The custom prompt is static text — it is not processed through Mustache templates. Tailor each role's prompt to its responsibilities:
462
+
463
+ - **Action prompts**: coding standards, architecture constraints, API endpoints, forbidden patterns, required tooling, domain terminology
464
+ - **Reviewer prompts**: quality gates, review checklists, coverage requirements, security policies, patterns to flag
465
+ - **Planner prompts**: planning methodology, decomposition guidelines, estimation rules, scope constraints
466
+ - **Risk prompts**: threat models, compliance requirements, security baselines, risk tolerance thresholds
467
+
468
+ 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.
469
+
470
+ ## Human In The Loop (HITL)
471
+
472
+ 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.
473
+
474
+ ```mermaid
475
+ sequenceDiagram
476
+ participant Agents as Agent Team
477
+ participant GH as GitHub PR
478
+ participant Orch as Orchestrator
479
+ participant Human as Human Reviewer
480
+
481
+ Agents->>GH: Open PR + review + approve
482
+ Orch->>GH: Request review + assign humans
483
+ Orch->>GH: Post summary @tagging reviewers
484
+ Orch->>Orch: Kill agents
485
+ Note over GH: awaiting_hitl
486
+ Human->>GH: Merge OR comment
487
+ alt human merges
488
+ Note over GH: Done
489
+ else human comments
490
+ Orch->>Orch: Spawn fresh agent
491
+ Agents->>GH: Address feedback
492
+ Orch->>GH: Re-request review
493
+ end
494
+ ```
495
+
496
+ ## Yin/Yang Review
497
+
498
+ 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).
499
+
500
+ | Theme | Yang (OpenAI) | Yin (Anthropic) | Council |
501
+ |-------|---------------|-----------------|---------|
502
+ | Transformers | Autobots | Decepticons | The Allspark |
503
+ | Pokemon | Fire types | Water types | Professor Oak |
504
+ | Marvel | Avengers | X-Men | S.H.I.E.L.D. |
505
+ | Digimon | Vaccine | Virus | Yggdrasil |
506
+ | Star Wars | Jedi | Sith | The Force |
507
+ | Lord of the Rings | Fellowship | Mordor | The Valar |
508
+ | Dragon Ball | Z Fighters | Villains | Grand Zeno |
509
+ | Avatar | Benders | Fire Nation | Raava |
510
+ | Zelda | Hyrule | Shadow | Hylia |
511
+
512
+ 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.
513
+
514
+ 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.
515
+
516
+ When cross-provider review isn't possible, the system falls back to single-side fresh-instance review while keeping action and reviewer identities distinct.
517
+
518
+ ## Distributed Coordination
519
+
520
+ 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.
521
+
522
+ ### The Problem
523
+
524
+ 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:
525
+ - **Evict immediately** — releasing claims and causing duplicate work if A's agents are still alive
526
+ - **Wait forever** — never reclaiming work from genuinely dead agents
527
+
528
+ ### Proof-of-Life Protocol
529
+
530
+ 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.
531
+
532
+ ```mermaid
533
+ sequenceDiagram
534
+ participant B as Orchestrator B
535
+ participant GH as GitHub
536
+ participant A as Orchestrator A
537
+
538
+ B->>GH: Detects claim by agent unknown to B
539
+ Note over B: Check recent GitHub activity first
540
+ alt recent activity found
541
+ Note over B: Skip — agent is probably alive
542
+ else no recent activity
543
+ B->>GH: Post themed proof-of-life request (council identity)
544
+ Note over A: Reactor tick detects request
545
+ A->>A: Run health(agent) check
546
+ A->>GH: Post themed alive response (agent identity)
547
+ B->>GH: Read alive response on next tick
548
+ alt alive response found
549
+ Note over B: Skip — agent confirmed alive
550
+ else no response within timeout
551
+ B->>GH: Release claim, dispatch new agent
552
+ end
553
+ end
554
+ ```
555
+
556
+ 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.
557
+
558
+ ### Four-Gate Eviction
559
+
560
+ Before evicting a foreign agent's claim, the detecting workflow runs four checks in order:
561
+
562
+ 1. **Local removal check** — Was this agent killed by our own stall detection? If yes, evict immediately (no network call needed).
563
+ 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.
564
+ 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.
565
+ 4. **Recent activity check** — Has anyone commented within the `proofOfLife.timeout` window? If yes, the agent is likely alive.
566
+ 5. **Post request** — No activity and no pending request → post a new proof-of-life request and wait until the next reactor tick.
567
+
568
+ ### Release Markers
569
+
570
+ 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.
571
+
572
+ ### Health Check
573
+
574
+ The `health()` method on the orchestrator evaluates multiple signals when responding to a proof-of-life request:
575
+
576
+ | Signal | Check | Result |
577
+ |--------|-------|--------|
578
+ | **Process** | Is the tmux pane alive? | `unhealthy` if dead |
579
+ | **State** | Is the agent dormant? | `unhealthy` if dormant |
580
+ | **Activity** | Last orchestrator interaction within stall timeout? | `unhealthy` if stale |
581
+ | **Output** | Captured terminal output length | Included for diagnostics |
582
+
583
+ ### Configuration
584
+
585
+ | Key | Default | Description |
586
+ |-----|---------|-------------|
587
+ | `proofOfLife.timeout` | `5m` | How long to wait for an alive response before evicting |
588
+
589
+ ```yaml
590
+ # loreli.yml
591
+ proofOfLife:
592
+ timeout: 5m # time window for proof-of-life responses
593
+ ```
594
+
595
+ ## Label Tracking
596
+
597
+ Every agent-created artifact (issue, PR, or discussion) gets labeled for tracking and attribution:
598
+
599
+ | Label | Example | Description |
600
+ |-------|---------|-------------|
601
+ | `loreli` | `loreli` | Marks all Loreli-managed items |
602
+ | `loreli:<provider>` | `loreli:anthropic` | AI provider that created the artifact |
603
+ | `model:<name>` | `model:claude-sonnet-4` | Human-readable model name |
604
+ | `loreli:<role>` | `loreli:action` | Agent role |
605
+ | `loreli:approved` | `loreli:approved` | Plan or PR approved |
606
+ | `loreli:changes-requested` | `loreli:changes-requested` | Revision required |
607
+
608
+ 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.
609
+
610
+ ## Machine-Readable Markers
611
+
612
+ 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.
613
+
614
+ ## Knowledge Capture
615
+
616
+ 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"`).
617
+
618
+ 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.
619
+
620
+ 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.
621
+
622
+ ## MCP Tools
623
+
624
+ ### Orchestration Tools (called by the user or parent agent)
625
+
626
+ | Tool | Description |
627
+ |------|-------------|
628
+ | `start` | Initialize repo — discover/scaffold files, MCP configs, labels, load config, create session |
629
+ | `environment` | Report tmux, backends, providers, review strategy |
630
+ | `add_agent` | Spawn agent with identity, backend, model, role |
631
+ | `agents` | Query agent team — `list` all agents or `check` health of one/all |
632
+ | `start_planning` | Activate planners with an objective, start reactor |
633
+ | `start_work` | Begin claim-work-review cycle |
634
+ | `team_status` | Dashboard of issues, PRs, agents, review loops, rate limits |
635
+ | `hitl` | Hand PR to human reviewers (Human In The Loop), shut down agents |
636
+ | `watch` | Check HITL PR for human feedback |
637
+ | `stop` | Stop an agent — `shutdown` (graceful) or `kill` (forced) |
638
+
639
+ ### Agent Tools (called by spawned agents via their MCP connection)
640
+
641
+ 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.
642
+
643
+ | Tool | Description |
644
+ |------|-------------|
645
+ | `plan` | Manage plan discussions — `create`, `revise`, `verdict`, `escalate` |
646
+ | `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. |
647
+ | `comment` | Post comments on current work item, or `claim` an issue |
648
+ | `read` | Read any issue, PR, or discussion by number with optional comments |
649
+ | `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 |
650
+
651
+ ## Environment Variables
652
+
653
+ Copy `.env.example` to `.env` and fill in the values. Variables set in the shell always take precedence.
654
+
655
+ | Variable | Required | Description |
656
+ |----------|----------|-------------|
657
+ | `GITHUB_TOKEN` | Yes | GitHub personal access token with `repo` scope |
658
+ | `LORELI_HOME` | No | Override `~/.loreli/` session storage path |
659
+ | `LORELI_LOG_LEVEL` | No | Log level: `error`, `warn`, `info` (default), `debug` |
660
+ | `LORELI_TEST_REPO` | No | GitHub repo for integration tests (`owner/name` format) |
661
+ | `LORELI_SESSION` | No | Set automatically for agent MCP servers — session ID |
662
+ | `LORELI_AGENT` | No | Set automatically for agent MCP servers — agent name |
663
+ | `LORELI_REPO` | No | Set automatically for agent MCP servers — target repo |
664
+
665
+ See [packages/config/README.md](packages/config/README.md) for the full env-to-config mapping and `loadEnv()` API.
666
+
667
+ ## Project Governance
668
+
669
+ - Contributing guide: [CONTRIBUTING.md](CONTRIBUTING.md)
670
+ - Code of Conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
671
+ - Security policy: [SECURITY.md](SECURITY.md)
672
+ - Changelog: [CHANGELOG.md](CHANGELOG.md)
100
673
 
101
674
  ## License
102
675