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.
- package/LICENSE +1 -1
- package/README.md +670 -97
- package/bin/loreli.js +89 -0
- package/package.json +74 -14
- package/packages/README.md +101 -0
- package/packages/action/README.md +98 -0
- package/packages/action/src/index.js +656 -0
- package/packages/agent/README.md +517 -0
- package/packages/agent/src/backends/claude.js +287 -0
- package/packages/agent/src/backends/codex.js +278 -0
- package/packages/agent/src/backends/cursor.js +294 -0
- package/packages/agent/src/backends/index.js +329 -0
- package/packages/agent/src/base.js +138 -0
- package/packages/agent/src/cli.js +198 -0
- package/packages/agent/src/factory.js +119 -0
- package/packages/agent/src/index.js +12 -0
- package/packages/agent/src/models.js +141 -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/config/README.md +833 -0
- package/packages/config/src/defaults.js +134 -0
- package/packages/config/src/index.js +192 -0
- package/packages/config/src/schema.js +273 -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 +1558 -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 +237 -0
- package/packages/knowledge/src/index.js +412 -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 +279 -0
- package/packages/mcp/instructions.md +121 -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 +453 -0
- package/packages/mcp/scaffolding/mcp-configs/.codex/config.toml +3 -0
- package/packages/mcp/scaffolding/mcp-configs/.cursor/mcp.json +11 -0
- package/packages/mcp/scaffolding/mcp-configs/.mcp.json +11 -0
- package/packages/mcp/scaffolding/pull-request.md +23 -0
- package/packages/mcp/src/index.js +571 -0
- package/packages/mcp/src/tools/agents.js +429 -0
- package/packages/mcp/src/tools/context.js +199 -0
- package/packages/mcp/src/tools/github.js +1199 -0
- package/packages/mcp/src/tools/hitl.js +149 -0
- package/packages/mcp/src/tools/index.js +17 -0
- package/packages/mcp/src/tools/start.js +835 -0
- package/packages/mcp/src/tools/status.js +146 -0
- package/packages/mcp/src/tools/work.js +124 -0
- package/packages/orchestrator/README.md +192 -0
- package/packages/orchestrator/src/index.js +1226 -0
- package/packages/planner/README.md +168 -0
- package/packages/planner/src/index.js +1166 -0
- package/packages/review/README.md +129 -0
- package/packages/review/src/index.js +1283 -0
- package/packages/risk/README.md +119 -0
- package/packages/risk/src/index.js +428 -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 +452 -0
- package/packages/workflow/README.md +313 -0
- package/packages/workflow/src/index.js +481 -0
- package/packages/workflow/src/proof-of-life.js +74 -0
- package/packages/workspace/README.md +143 -0
- package/packages/workspace/src/index.js +1076 -0
- package/index.js +0 -8
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loreli marker system — machine-readable HTML comment metadata for GitHub content.
|
|
3
|
+
*
|
|
4
|
+
* Marker format: `<!-- loreli:TYPE key="value" key="value" -->`
|
|
5
|
+
*
|
|
6
|
+
* Decouples workflow-state detection from human-visible text so themed
|
|
7
|
+
* messages can change freely without breaking parsing logic.
|
|
8
|
+
*
|
|
9
|
+
* @module loreli/marker
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const PREFIX = 'loreli';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* HTML-entity-encode a marker value so `"`, `&`, `<`, and `>` are safe
|
|
16
|
+
* inside the `key="value"` format within an HTML comment.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} value - Raw value string.
|
|
19
|
+
* @returns {string} Encoded value (no literal `"`, `&`, `<`, or `>`).
|
|
20
|
+
*/
|
|
21
|
+
function encode(value) {
|
|
22
|
+
return value
|
|
23
|
+
.replaceAll('&', '&')
|
|
24
|
+
.replaceAll('"', '"')
|
|
25
|
+
.replaceAll('<', '<')
|
|
26
|
+
.replaceAll('>', '>');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Decode HTML entities produced by {@link encode} back to raw characters.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} value - Encoded value string.
|
|
33
|
+
* @returns {string} Original value with entities resolved.
|
|
34
|
+
*/
|
|
35
|
+
function decode(value) {
|
|
36
|
+
return value
|
|
37
|
+
.replaceAll('"', '"')
|
|
38
|
+
.replaceAll('<', '<')
|
|
39
|
+
.replaceAll('>', '>')
|
|
40
|
+
.replaceAll('&', '&');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Matches a loreli marker with a specific type.
|
|
45
|
+
* Capture group 1: the key-value payload (may be empty).
|
|
46
|
+
*
|
|
47
|
+
* @param {string} type - Marker type to target.
|
|
48
|
+
* @returns {RegExp}
|
|
49
|
+
*/
|
|
50
|
+
function regex(type) {
|
|
51
|
+
return new RegExp(`<!-- ${PREFIX}:${type}((?:\\s+\\w+="[^"]*")*) -->`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Parses `key="value"` pairs from the raw payload string captured by {@link regex}.
|
|
56
|
+
* Values are HTML-entity-decoded so callers receive the original strings.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} raw - Space-separated key="value" string.
|
|
59
|
+
* @returns {Object<string, string>}
|
|
60
|
+
*/
|
|
61
|
+
function pairs(raw) {
|
|
62
|
+
const data = {};
|
|
63
|
+
const re = /(\w+)="([^"]*)"/g;
|
|
64
|
+
let m;
|
|
65
|
+
while ((m = re.exec(raw)) !== null) data[m[1]] = decode(m[2]);
|
|
66
|
+
return data;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Produces a loreli marker string. Values are HTML-entity-encoded so
|
|
71
|
+
* special characters (`"`, `&`, `<`, `>`) do not break the marker format
|
|
72
|
+
* or prematurely close the HTML comment.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} type - Marker type (e.g. 'claim', 'signature', 'agent').
|
|
75
|
+
* @param {Object<string, string>} [data] - Key-value pairs to embed.
|
|
76
|
+
* @returns {string} An HTML comment marker.
|
|
77
|
+
* @throws {Error} If type is falsy or empty.
|
|
78
|
+
*/
|
|
79
|
+
export function mark(type, data) {
|
|
80
|
+
if (!type) throw new Error('type is required');
|
|
81
|
+
|
|
82
|
+
const entries = Object.entries(data ?? {});
|
|
83
|
+
const payload = entries.length
|
|
84
|
+
? ' ' + entries.map(function pair([k, v]) { return `${k}="${encode(v)}"`; }).join(' ')
|
|
85
|
+
: '';
|
|
86
|
+
|
|
87
|
+
return `<!-- ${PREFIX}:${type}${payload} -->`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Checks whether a body contains a marker of the given type.
|
|
92
|
+
*
|
|
93
|
+
* @param {string | null | undefined} body - GitHub comment/PR/discussion body.
|
|
94
|
+
* @param {string} type - Marker type to look for.
|
|
95
|
+
* @returns {boolean}
|
|
96
|
+
*/
|
|
97
|
+
export function has(body, type) {
|
|
98
|
+
if (!body) return false;
|
|
99
|
+
return regex(type).test(body);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Extracts the key-value data from the first marker of the given type.
|
|
104
|
+
*
|
|
105
|
+
* @param {string | null | undefined} body - GitHub comment/PR/discussion body.
|
|
106
|
+
* @param {string} type - Marker type to extract.
|
|
107
|
+
* @returns {Object<string, string> | null} Parsed data, or null if not found.
|
|
108
|
+
*/
|
|
109
|
+
export function parse(body, type) {
|
|
110
|
+
if (!body) return null;
|
|
111
|
+
const m = body.match(regex(type));
|
|
112
|
+
if (!m) return null;
|
|
113
|
+
return pairs(m[1]);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Removes the first marker of the given type and everything after it,
|
|
118
|
+
* trimming trailing whitespace from the remaining content.
|
|
119
|
+
*
|
|
120
|
+
* @param {string | null | undefined} body - GitHub comment/PR/discussion body.
|
|
121
|
+
* @param {string} type - Marker type to strip from.
|
|
122
|
+
* @returns {string | null | undefined} Body with marker and trailing content removed.
|
|
123
|
+
*/
|
|
124
|
+
export function strip(body, type) {
|
|
125
|
+
if (body == null || body === '') return body;
|
|
126
|
+
const idx = body.search(regex(type));
|
|
127
|
+
if (idx === -1) return body;
|
|
128
|
+
return body.slice(0, idx).trimEnd();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Removes the last marker of the given type and everything after it,
|
|
133
|
+
* trimming trailing whitespace from the remaining content.
|
|
134
|
+
*
|
|
135
|
+
* Use when multiple markers exist and only the trailing one should be
|
|
136
|
+
* removed (e.g. duplicate signatures at end of body).
|
|
137
|
+
*
|
|
138
|
+
* @param {string | null | undefined} body - GitHub comment/PR/discussion body.
|
|
139
|
+
* @param {string} type - Marker type to strip from.
|
|
140
|
+
* @returns {string | null | undefined} Body with last marker and trailing content removed.
|
|
141
|
+
*/
|
|
142
|
+
export function stripLast(body, type) {
|
|
143
|
+
if (body == null || body === '') return body;
|
|
144
|
+
const re = new RegExp(regex(type).source, 'g');
|
|
145
|
+
let lastIdx = -1;
|
|
146
|
+
let m;
|
|
147
|
+
while ((m = re.exec(body)) !== null) lastIdx = m.index;
|
|
148
|
+
if (lastIdx === -1) return body;
|
|
149
|
+
return body.slice(0, lastIdx).trimEnd();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Removes content between paired markers of the given type.
|
|
154
|
+
*
|
|
155
|
+
* Finds the opening `<!-- loreli:TYPE ... -->` and the closing
|
|
156
|
+
* `<!-- loreli:TYPE-end -->`, removes both markers and everything
|
|
157
|
+
* between them, and collapses extra blank lines at the join point.
|
|
158
|
+
*
|
|
159
|
+
* Unlike {@link strip}, which removes a marker and everything after it,
|
|
160
|
+
* `excise` removes only the delimited section and preserves content on
|
|
161
|
+
* both sides. Designed for trace blocks and other self-contained sections
|
|
162
|
+
* embedded within larger bodies.
|
|
163
|
+
*
|
|
164
|
+
* @param {string | null | undefined} body - GitHub comment/PR/discussion body.
|
|
165
|
+
* @param {string} type - Marker type to excise (matches TYPE and TYPE-end).
|
|
166
|
+
* @returns {string | null | undefined} Body with the marker-delimited section removed.
|
|
167
|
+
*/
|
|
168
|
+
export function excise(body, type) {
|
|
169
|
+
if (body == null || body === '') return body;
|
|
170
|
+
const startIdx = body.search(regex(type));
|
|
171
|
+
if (startIdx === -1) return body;
|
|
172
|
+
|
|
173
|
+
const endMarker = new RegExp(`<!-- ${PREFIX}:${type}-end -->`);
|
|
174
|
+
const after = body.slice(startIdx);
|
|
175
|
+
const endMatch = endMarker.exec(after);
|
|
176
|
+
if (!endMatch) return body;
|
|
177
|
+
|
|
178
|
+
const endIdx = startIdx + endMatch.index + endMatch[0].length;
|
|
179
|
+
const before = body.slice(0, startIdx);
|
|
180
|
+
const rest = body.slice(endIdx);
|
|
181
|
+
|
|
182
|
+
// Collapse extra blank lines at the join point
|
|
183
|
+
return (before.replace(/\n+$/, '') + rest.replace(/^\n+/, '\n')).trim();
|
|
184
|
+
}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# loreli/mcp
|
|
2
|
+
|
|
3
|
+
MCP server for agentic team orchestration via GitHub. Exposes orchestration tools, manages agent lifecycle, and provides a CLI entry point.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
Run this command to start the MCP server over stdio when you want to connect a client directly; the process should stay running and wait for MCP messages.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
loreli mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Before using the CLI tool commands below, configure an MCP server entry named `loreli` in your client or global config (for example `~/.cursor/mcp.json`, `~/.claude/.mcp.json`, or `~/.codex/config.toml`). This matters because the CLI resolves tool invocations through that server entry, and without it the commands will fail. When configured correctly, you should see the tool list printed and each command should execute successfully.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
loreli tools list
|
|
17
|
+
loreli tools start --repo owner/repo
|
|
18
|
+
loreli tools team_status
|
|
19
|
+
loreli tools agents --action check
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
All MCP tools are automatically available as CLI commands through `@mcp-layer/cli` once the `loreli` MCP server entry is configured. Run `loreli --help` for the full list.
|
|
23
|
+
|
|
24
|
+
## API Reference
|
|
25
|
+
|
|
26
|
+
### `Loreli` Class
|
|
27
|
+
|
|
28
|
+
The main server class following the uprising start pattern.
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import { Loreli } from 'loreli/mcp';
|
|
32
|
+
|
|
33
|
+
const loreli = new Loreli();
|
|
34
|
+
await loreli.start(); // connects stdio transport
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
#### `loreli.loadInstructions()` -> string
|
|
38
|
+
|
|
39
|
+
Loads the `instructions.md` file that is returned to MCP clients via the protocol's `instructions` field. This gives connected agents context about how Loreli works, its workflow, and review expectations.
|
|
40
|
+
|
|
41
|
+
#### `loreli.tools(tools)`
|
|
42
|
+
|
|
43
|
+
Register tool definitions. Each tool is `{ title, description, schema, exec }`.
|
|
44
|
+
|
|
45
|
+
#### `loreli.prompts(prompts)` / `loreli.resources(resources)`
|
|
46
|
+
|
|
47
|
+
Register prompt and resource definitions.
|
|
48
|
+
|
|
49
|
+
#### `loreli.start(transport?)` -> McpServer
|
|
50
|
+
|
|
51
|
+
Start the server. Defaults to stdio transport.
|
|
52
|
+
|
|
53
|
+
## MCP Tools
|
|
54
|
+
|
|
55
|
+
All tools are visible at all times. No progressive disclosure — every tool is available from the first connection.
|
|
56
|
+
|
|
57
|
+
### Start & Environment
|
|
58
|
+
|
|
59
|
+
| Tool | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| `start` | Initialize orchestration for a target GitHub repo. Validates access, discovers/scaffolds templates, creates project board. Idempotent — safe to re-run. |
|
|
62
|
+
| `environment` | Report detected environment: tmux, backends, providers, review strategy. |
|
|
63
|
+
|
|
64
|
+
### Team Management
|
|
65
|
+
|
|
66
|
+
| Tool | Description |
|
|
67
|
+
|------|-------------|
|
|
68
|
+
| `add_agent` | Add an agent. Params: `provider` (`openai`, `anthropic`, `cursor-openai`, `cursor-anthropic`), `role` (`planner`, `action`, `reviewer`), `model`, `theme`. |
|
|
69
|
+
| `agents` | Query agent team state. Actions: `list` (show all agents with state, identity, role, and terminal output; optional `lines` param, default 40), `check` (liveness check for one or all agents). |
|
|
70
|
+
| `start_planning` | Activate planner agents to analyze the repo and create draft work items. Accepts an `objective` to guide the planner. |
|
|
71
|
+
| `start_work` | Begin action/review cycle. Action agents claim issues, do work, create PRs. Review agents are auto-assigned via yin/yang pairing. |
|
|
72
|
+
| `team_status` | Dashboard: issues, PRs, agent states with terminal snapshots (last 20 lines), review loops, PRs awaiting human review, and GitHub API rate limits. |
|
|
73
|
+
| `escalate` | Signal a concern or feature idea to the planner queue. Creates a draft on the project board. |
|
|
74
|
+
|
|
75
|
+
### Human In The Loop (HITL)
|
|
76
|
+
|
|
77
|
+
| Tool | Description |
|
|
78
|
+
|------|-------------|
|
|
79
|
+
| `hitl` | Hand off a PR to human reviewers (Human In The Loop). Requests review, assigns users, posts summary comment tagging reviewers. Kills agents to conserve resources. |
|
|
80
|
+
| `watch` | Check an HITL PR for new human feedback. Filters out agent comments. Returns comments posted after the HITL timestamp. |
|
|
81
|
+
|
|
82
|
+
### Agent Lifecycle
|
|
83
|
+
|
|
84
|
+
| Tool | Description |
|
|
85
|
+
|------|-------------|
|
|
86
|
+
| `stop` | Stop an agent by name. Actions: `shutdown` (graceful, agent finishes current work then exits; escalates to kill after timeout), `kill` (immediate forced termination of tmux pane). |
|
|
87
|
+
|
|
88
|
+
## Start Repair
|
|
89
|
+
|
|
90
|
+
Start is an idempotent repair operation. Every invocation discovers which required files exist and scaffolds any that are missing. Safe to re-run.
|
|
91
|
+
|
|
92
|
+
```mermaid
|
|
93
|
+
flowchart TD
|
|
94
|
+
Discover["discover templates via hub.read"] --> Check{"Missing files?"}
|
|
95
|
+
Check -->|yes| Scaffold["scaffold via hub.write"]
|
|
96
|
+
Check -->|no| Load
|
|
97
|
+
Scaffold --> Load["config.load via hub"]
|
|
98
|
+
Load --> Merge["config.merge(args)"]
|
|
99
|
+
Merge --> Session["storage.init(session, config)"]
|
|
100
|
+
Session --> Report["Report: found + scaffolded"]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Required Files
|
|
104
|
+
|
|
105
|
+
| File | Scaffold Source | Discover Key |
|
|
106
|
+
|------|----------------|--------------|
|
|
107
|
+
| `.github/pull_request_template.md` | `scaffolding/pull-request.md` | `pr` |
|
|
108
|
+
| `.github/ISSUE_TEMPLATE/` | `scaffolding/ISSUE_TEMPLATE/` | `issue` |
|
|
109
|
+
| `loreli.yml` | `scaffolding/loreli.yml` | `config` |
|
|
110
|
+
|
|
111
|
+
## Scaffolding Templates
|
|
112
|
+
|
|
113
|
+
Default templates for empty repos, read from `scaffolding/`:
|
|
114
|
+
|
|
115
|
+
- `pull-request.md` — PR template with Summary, Changes, Testing, Issue Reference, Sign-off
|
|
116
|
+
- `ISSUE_TEMPLATE/loreli.yml` — Structured issue form mirroring the planner output format: Objective, Acceptance Criteria, Testing Strategy, Scope Boundaries, Dependencies, Estimated Complexity. Auto-applies the `loreli` label so issues enter the dispatch pipeline immediately.
|
|
117
|
+
- `ISSUE_TEMPLATE/config.yml` — Issue template configuration (blank issues disabled to ensure all issues use the structured template and receive the `loreli` label)
|
|
118
|
+
- `loreli.yml` — Default config with all keys documented via inline comments
|
|
119
|
+
|
|
120
|
+
Issue templates use the [new YAML-based issue form workflow](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository) instead of the deprecated single-file Markdown format. The template guides authors toward writing agent-actionable prompts with mandatory acceptance criteria and testing strategy, matching the same structure the planner produces.
|
|
121
|
+
|
|
122
|
+
## Orchestrator
|
|
123
|
+
|
|
124
|
+
The `Orchestrator` class manages the full lifecycle:
|
|
125
|
+
|
|
126
|
+
1. **Plan** — Planner creates drafts on project board, reviewer challenges
|
|
127
|
+
2. **Promote** — Approved drafts become real issues
|
|
128
|
+
3. **Action** — Agents claim issues, create PRs
|
|
129
|
+
4. **Review** — Cross-provider adversarial review
|
|
130
|
+
5. **HITL** (optional) — Hand off to human reviewers, kill agents
|
|
131
|
+
6. **Merge** — Dual sign-off triggers merge (auto), or human merges (HITL)
|
|
132
|
+
|
|
133
|
+
### Orchestrator Lifecycle
|
|
134
|
+
|
|
135
|
+
```mermaid
|
|
136
|
+
stateDiagram-v2
|
|
137
|
+
[*] --> Init: start
|
|
138
|
+
Init --> Planning: start_planning(objective)
|
|
139
|
+
Planning --> Promoting: drafts approved
|
|
140
|
+
Promoting --> Working: start_work
|
|
141
|
+
Working --> Reviewing: PR opened
|
|
142
|
+
Reviewing --> Working: feedback
|
|
143
|
+
Reviewing --> Gating: dual sign-off
|
|
144
|
+
Gating --> Merged: auto-merge
|
|
145
|
+
Gating --> AwaitingHuman: HITL
|
|
146
|
+
AwaitingHuman --> Merged: human merges
|
|
147
|
+
AwaitingHuman --> Rework: human comments
|
|
148
|
+
Rework --> Reviewing: fresh agent
|
|
149
|
+
Merged --> [*]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Stall Detection (Escalation Tiers)
|
|
153
|
+
|
|
154
|
+
The orchestrator monitors agents for inactivity with three escalation tiers:
|
|
155
|
+
|
|
156
|
+
| Tier | Trigger | Action |
|
|
157
|
+
|------|---------|--------|
|
|
158
|
+
| **Nudge** | 1x `timeouts.stall` | Send a message to the agent asking for status |
|
|
159
|
+
| **Warning** | 2x `timeouts.stall` | Post a visible GitHub comment on the agent's claimed issue |
|
|
160
|
+
| **Reassign** | 3x `timeouts.stall` | Kill the agent, release all claimed issues, emit event |
|
|
161
|
+
|
|
162
|
+
When an agent is killed via stall detection (tier 3), its claimed issues are released so `start_work` can re-assign them to a fresh agent.
|
|
163
|
+
|
|
164
|
+
### Issue Reassignment
|
|
165
|
+
|
|
166
|
+
When an agent is killed (`stop` action: `kill`) or shut down (`stop` action: `shutdown`), any GitHub issues claimed by that agent are automatically released. This prevents dead agents from blocking work:
|
|
167
|
+
|
|
168
|
+
1. Scan open issues for the agent's claim comments
|
|
169
|
+
2. Post a release comment on each claimed issue
|
|
170
|
+
3. Remove agent-specific labels
|
|
171
|
+
4. Issue becomes available for re-claim by `start_work`
|
|
172
|
+
|
|
173
|
+
### Structured Shutdown Protocol
|
|
174
|
+
|
|
175
|
+
Agent shutdown follows a 3-phase protocol:
|
|
176
|
+
|
|
177
|
+
1. **Request** — Send a structured shutdown message with a unique `requestId` and optional reason
|
|
178
|
+
2. **Poll** — Wait for the agent to acknowledge (exits or transitions to dormant)
|
|
179
|
+
3. **Cleanup** — Force stop, release claimed issues, remove from registry
|
|
180
|
+
|
|
181
|
+
The `requestId` prevents confusion between concurrent shutdown requests. If the agent doesn't acknowledge within the timeout, it is force-stopped.
|
|
182
|
+
|
|
183
|
+
### Plan Review
|
|
184
|
+
|
|
185
|
+
When `start_planning` dispatches to planner agents, a reviewer agent (if available) is automatically assigned to adversarially review the resulting drafts. This leverages the yin/yang pairing to get cross-provider plan review before drafts are promoted to issues.
|
|
186
|
+
|
|
187
|
+
### Human In The Loop (HITL)
|
|
188
|
+
|
|
189
|
+
```mermaid
|
|
190
|
+
sequenceDiagram
|
|
191
|
+
participant Action as ActionAgent
|
|
192
|
+
participant Reviewer as ReviewAgent
|
|
193
|
+
participant GH as GitHub PR
|
|
194
|
+
participant Orch as Orchestrator
|
|
195
|
+
participant Human as Human Reviewer
|
|
196
|
+
|
|
197
|
+
Action->>GH: Opens PR
|
|
198
|
+
Reviewer->>GH: Reviews PR
|
|
199
|
+
Action->>GH: Addresses feedback
|
|
200
|
+
Reviewer->>GH: Approves
|
|
201
|
+
Action->>GH: Signs off
|
|
202
|
+
Orch->>Orch: config.get merge.hitl
|
|
203
|
+
alt hitl = false
|
|
204
|
+
Orch->>GH: Merge PR
|
|
205
|
+
else hitl = true
|
|
206
|
+
Orch->>GH: Request review + assign reviewers
|
|
207
|
+
Orch->>GH: Post summary comment @tagging reviewers
|
|
208
|
+
Orch->>Orch: Kill both agents
|
|
209
|
+
Note over GH: awaiting_hitl
|
|
210
|
+
Human->>GH: Merge OR comment
|
|
211
|
+
alt human merges
|
|
212
|
+
Note over GH: Done
|
|
213
|
+
else human comments
|
|
214
|
+
Orch->>Orch: Spawn fresh agent
|
|
215
|
+
Action->>GH: Address feedback + push
|
|
216
|
+
Orch->>GH: Re-request + re-assign
|
|
217
|
+
Orch->>Orch: Kill agent
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
HITL is activated when `loreli.yml` has a non-empty `reviewers` list or `merge.hitl` is set to `true`.
|
|
223
|
+
|
|
224
|
+
## CLI
|
|
225
|
+
|
|
226
|
+
The CLI is powered by `@mcp-layer/cli`, which automatically exposes all MCP tools as CLI commands.
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
# Start the MCP server (required when used as MCP server)
|
|
230
|
+
loreli mcp
|
|
231
|
+
|
|
232
|
+
# All tools are available as subcommands
|
|
233
|
+
loreli tools list
|
|
234
|
+
loreli tools start --repo owner/repo
|
|
235
|
+
loreli tools add_agent --provider anthropic --role action
|
|
236
|
+
loreli tools team_status
|
|
237
|
+
loreli tools agents --action check --name optimus-0
|
|
238
|
+
|
|
239
|
+
# Default (no args) shows help
|
|
240
|
+
loreli
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Input Validation
|
|
244
|
+
|
|
245
|
+
All tool handlers validate inputs before any side effects using `check.*` from `loreli/config`:
|
|
246
|
+
|
|
247
|
+
| Validator | Rule |
|
|
248
|
+
|-----------|------|
|
|
249
|
+
| `check.repo(str)` | Must match `owner/name` format |
|
|
250
|
+
| `check.name(str)` | Alphanumeric + hyphens/underscores, max 64 chars |
|
|
251
|
+
| `check.role(str)` | Must be `planner`, `action`, or `reviewer` |
|
|
252
|
+
| `check.theme(str)` | Must be one of the supported themes (`transformers`, `pokemon`, `marvel`, `digimon`, `starwars`, `lotr`, `dragonball`, `avatar`, `zelda`) |
|
|
253
|
+
| `check.provider(str)` | Must be `openai`, `anthropic`, `cursor-openai`, or `cursor-anthropic` |
|
|
254
|
+
| `check.positive(n, label)` | Must be a finite positive number |
|
|
255
|
+
|
|
256
|
+
Invalid inputs throw immediately with descriptive error messages before any GitHub API calls or state mutations.
|
|
257
|
+
|
|
258
|
+
## Dynamic Tool Descriptions
|
|
259
|
+
|
|
260
|
+
After start discovers available backends, the `add_agent` tool description is dynamically updated to list available backends, model aliases, and providers. MCP clients receive a `tools/list_changed` notification so they can refresh the tool list.
|
|
261
|
+
|
|
262
|
+
## Client Detection
|
|
263
|
+
|
|
264
|
+
The server identifies the connected MCP client via the standard `initialize` handshake. The `clientInfo` field (name, version) from the handshake is used to build a lightweight `Identity` for stamping tool-originated content. This replaces the previous sampling-based probe which was fragile and optional.
|
|
265
|
+
|
|
266
|
+
## Error Handling
|
|
267
|
+
|
|
268
|
+
| Scenario | Behavior |
|
|
269
|
+
|----------|----------|
|
|
270
|
+
| Spawn fails | All steps rolled back in reverse order, identity released, error propagated |
|
|
271
|
+
| Agent stalls | Tier 1: nudge, Tier 2: GitHub comment, Tier 3: kill and reassign |
|
|
272
|
+
| Shutdown timeout | Force stop after timeout, issues released |
|
|
273
|
+
| Agent killed | Issues reassigned, identity released, labels cleaned |
|
|
274
|
+
| Invalid tool input | Descriptive error thrown before any side effects |
|
|
275
|
+
| No backends found | Clear error with installation guidance |
|
|
276
|
+
| Hub unavailable | Tool returns error with guidance |
|
|
277
|
+
| No planner agents | `start_planning` returns error |
|
|
278
|
+
| No unclaimed issues | `start_work` returns "no unclaimed issues" message |
|
|
279
|
+
| tmux missing | `loreli mcp` exits with install instructions |
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
You are connected to **Loreli**, an agentic team orchestration server that coordinates AI agents using GitHub as the collaboration layer.
|
|
2
|
+
|
|
3
|
+
<overview>
|
|
4
|
+
|
|
5
|
+
Loreli manages teams of AI agents that work on GitHub repositories. Issues are tasks, pull requests are deliverables, discussions are plans, comments are communication, and reviews are quality gates.
|
|
6
|
+
|
|
7
|
+
### Workflow
|
|
8
|
+
|
|
9
|
+
1. **Start**: Point Loreli at a target GitHub repository. It validates access, discovers existing files, and scaffolds any missing ones (PR template, issue template, `loreli.yml`). This is idempotent — safe to re-run.
|
|
10
|
+
2. **Plan**: Planner agents create plan discussions in the Loreli category using the `plan` tool. A polar-opposite reviewer challenges the plan using the `plan` tool (action: `verdict`).
|
|
11
|
+
3. **Action**: Action agents claim approved issues (first-comment-wins), create branches, implement work, and open PRs using the `pr` tool.
|
|
12
|
+
4. **Review**: Cross-provider reviewers assess PRs adversarially using the `pr` tool (action: `review`). Feedback is addressed in iteration loops.
|
|
13
|
+
5. **Human In The Loop (HITL)** (optional): If `loreli.yml` has `reviewers` configured, PRs are handed off to human reviewers after agent approval. Agents are shut down while awaiting human decision.
|
|
14
|
+
6. **Merge**: Dual sign-off triggers merge (auto), or human merges manually (HITL). Agents go dormant or claim new work.
|
|
15
|
+
|
|
16
|
+
### Configuration
|
|
17
|
+
|
|
18
|
+
Each target repository can have a `loreli.yml` in its root to configure orchestration behavior — theme, merge method, human reviewers, timeouts, and more. If the file doesn't exist, start scaffolds a default one. Start params override `loreli.yml` values.
|
|
19
|
+
|
|
20
|
+
### Agent Identity
|
|
21
|
+
|
|
22
|
+
Agents are assigned themed identities (Transformers, Pokemon, Marvel, Digimon) with yin/yang provider pairing. OpenAI agents get one faction, Anthropic agents get the opposing faction. This creates adversarial quality checks.
|
|
23
|
+
|
|
24
|
+
### Backends
|
|
25
|
+
|
|
26
|
+
Loreli supports multiple backends: Claude (interactive, Anthropic), Cursor Agent (interactive, multi-provider), Codex (interactive, OpenAI). The `environment` tool shows which backends are available. When adding agents, use `provider: "anthropic"` for Claude, `provider: "openai"` for Codex, or `provider: "multi"` for Cursor Agent (which can run models from any provider).
|
|
27
|
+
|
|
28
|
+
</overview>
|
|
29
|
+
|
|
30
|
+
<protocols>
|
|
31
|
+
|
|
32
|
+
### Claim Protocol
|
|
33
|
+
|
|
34
|
+
Issues are claimed via first-comment-wins. When an agent wants to work on an issue, it posts a claim comment using the `comment` tool. The first claim comment's author is the assigned agent.
|
|
35
|
+
|
|
36
|
+
### Review Expectations
|
|
37
|
+
|
|
38
|
+
- Address all review feedback before requesting re-review.
|
|
39
|
+
- Both the action agent and review agent must sign off for merge.
|
|
40
|
+
- Escalate scope concerns using the `plan` tool (action: `escalate`).
|
|
41
|
+
|
|
42
|
+
### Human In The Loop (HITL)
|
|
43
|
+
|
|
44
|
+
When configured, after both agents sign off:
|
|
45
|
+
|
|
46
|
+
1. Loreli requests review from the configured human reviewers.
|
|
47
|
+
2. Agents are shut down to conserve resources.
|
|
48
|
+
3. If the human merges, the workflow is complete.
|
|
49
|
+
4. If the human posts comments, Loreli spawns a fresh agent to address the feedback and re-requests review.
|
|
50
|
+
|
|
51
|
+
### Communication
|
|
52
|
+
|
|
53
|
+
All communication happens through GitHub: issue comments, PR comments, discussion comments, and reviews. There are no private channels — everything is visible and auditable.
|
|
54
|
+
|
|
55
|
+
</protocols>
|
|
56
|
+
|
|
57
|
+
<tool_contract>
|
|
58
|
+
|
|
59
|
+
## Agent Tool Contract
|
|
60
|
+
|
|
61
|
+
When you are a spawned agent (planner, action, or reviewer), use the Loreli MCP tools for all GitHub operations. Your identity, repository, and current work item are resolved automatically from your session.
|
|
62
|
+
|
|
63
|
+
### Available Agent Tools
|
|
64
|
+
|
|
65
|
+
| Tool | Actions | Used By |
|
|
66
|
+
|------|---------|---------|
|
|
67
|
+
| **plan** | `create`, `revise`, `verdict`, `escalate` | Planner creates/revises; Reviewer renders verdict; Any role escalates |
|
|
68
|
+
| **pr** | `create`, `review` | Action creates PRs; Reviewer submits reviews |
|
|
69
|
+
| **comment** | (none) | Any role posts comments on their current work item |
|
|
70
|
+
| **context** | `blame`, `history`, `search`, `patterns` | Any role looks up code context, decision history, and feedback patterns |
|
|
71
|
+
|
|
72
|
+
### Context Resolution
|
|
73
|
+
|
|
74
|
+
Your session automatically provides:
|
|
75
|
+
- **Repository**: The target repo you are assigned to.
|
|
76
|
+
- **Identity**: Your themed identity with stamp and labels.
|
|
77
|
+
- **Role**: Your role (planner, action, reviewer).
|
|
78
|
+
- **Task**: Your current work item (discussion number, issue number, or PR number).
|
|
79
|
+
|
|
80
|
+
You do not need to provide these values — the tools resolve them from your session.
|
|
81
|
+
|
|
82
|
+
### Role Enforcement
|
|
83
|
+
|
|
84
|
+
Tools enforce role boundaries server-side:
|
|
85
|
+
|
|
86
|
+
| Action | Allowed Role | Blocked Roles |
|
|
87
|
+
|--------|-------------|---------------|
|
|
88
|
+
| `plan/create`, `plan/revise` | planner | action, reviewer |
|
|
89
|
+
| `plan/verdict` | reviewer | planner, action |
|
|
90
|
+
| `pr/create` | action | planner, reviewer |
|
|
91
|
+
| `pr/review` | reviewer | planner, action |
|
|
92
|
+
| `plan/escalate`, `comment` | any | — |
|
|
93
|
+
| `context/*` | any | — |
|
|
94
|
+
|
|
95
|
+
An action agent cannot approve its own PR. A planner cannot approve its own plan. The antagonist (opposing-provider reviewer) is always mandatory and auto-enlisted when missing.
|
|
96
|
+
|
|
97
|
+
### Context Tool
|
|
98
|
+
|
|
99
|
+
The `context` tool resolves code context — tracing lines to the PRs, issues, and discussions that shaped them. Use it to understand why code exists before changing it.
|
|
100
|
+
|
|
101
|
+
| Action | What it does |
|
|
102
|
+
|--------|-------------|
|
|
103
|
+
| `blame` | Trace a file+line to the commit, author, and associated PRs |
|
|
104
|
+
| `history` | View the commit history for a file with linked PR references |
|
|
105
|
+
| `search` | Search issues and PRs by keyword to find past decisions |
|
|
106
|
+
| `patterns` | View recurring review feedback patterns across PRs and plan discussions |
|
|
107
|
+
|
|
108
|
+
Also available via CLI: `loreli tools context --action blame --file <path> --line <N>`
|
|
109
|
+
|
|
110
|
+
</tool_contract>
|
|
111
|
+
|
|
112
|
+
<rules>
|
|
113
|
+
|
|
114
|
+
1. **Never bypass the tools**: All GitHub interactions must go through Loreli MCP tools. Direct `gh` CLI, REST, or GraphQL calls bypass stamping and label enforcement.
|
|
115
|
+
2. **Never manage labels manually**: Labels are applied automatically by the tools. Do not add, remove, or modify `loreli:*` labels yourself.
|
|
116
|
+
3. **Stay within scope**: If you discover work outside your current assignment, use the `plan` tool (action: `escalate`) to flag it.
|
|
117
|
+
4. **Respect your role**: Only use actions permitted for your role. Attempting unauthorized actions wastes tokens and time.
|
|
118
|
+
5. **Honor repository policy files**: If `AGENTS.md` exists in the repository root, treat it as authoritative repository policy input.
|
|
119
|
+
6. **Follow role prompt quality gates**: Testing and style-quality requirements are enforced in role-specific prompts and review flows; do not bypass them.
|
|
120
|
+
|
|
121
|
+
</rules>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: loreli-context
|
|
3
|
+
description: Use when modifying unfamiliar code, investigating patterns, or reviewing PRs — resolves code to its full decision chain via git blame, PR history, issue tracking, and discussion threads
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Loreli Context
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Loreli maintains a complete decision chain for every line of code: commits link to PRs, PRs link to issues, and issues link to planning discussions. This skill teaches you how to query that chain.
|
|
11
|
+
|
|
12
|
+
**Core principle:** Understand why code exists before changing it.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- Before modifying code you did not write
|
|
17
|
+
- When encountering a pattern or convention you do not understand
|
|
18
|
+
- When reviewing PRs with unclear rationale
|
|
19
|
+
- Before making architectural decisions (check what has been tried before)
|
|
20
|
+
- When debugging to understand historical context of a module
|
|
21
|
+
|
|
22
|
+
## CLI Commands
|
|
23
|
+
|
|
24
|
+
All commands are run in the terminal via the loreli CLI:
|
|
25
|
+
|
|
26
|
+
### Blame — "Why was this line written?"
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
loreli tools context --action blame --file <path> --line <N>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Traces a specific line to the commit that created it, the PR that landed it, the issue it addressed, and the discussion where it was planned. Includes agent traces if available.
|
|
33
|
+
|
|
34
|
+
### History — "What decisions shaped this file?"
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
loreli tools context --action history --file <path> --limit <N>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Returns recent commits touching a file with their associated PRs. Default limit is 10. Use this to understand the evolution of a module before making changes.
|
|
41
|
+
|
|
42
|
+
### Search — "What do we know about X?"
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
loreli tools context --action search --query "<keywords>"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Searches across issues, PRs, and discussions for matching content. Use this to find prior discussions about a concept, pattern, or decision.
|
|
49
|
+
|
|
50
|
+
### Patterns — "What recurring review themes exist?"
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
loreli tools context --action patterns --category <category>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Shows recurring feedback patterns across PR reviews and plan discussion verdicts. Categories: naming, architecture, testing, documentation, performance, security. Each pattern lists its source refs as `PR #N` or `Discussion #N` so you can trace feedback origin. Check this before submitting PRs to avoid known issues.
|
|
57
|
+
|
|
58
|
+
## Documentation Requirements
|
|
59
|
+
|
|
60
|
+
When working on code, maintain these documentation standards:
|
|
61
|
+
|
|
62
|
+
### Architectural Changes
|
|
63
|
+
|
|
64
|
+
If you add new packages, modules, or change data flow:
|
|
65
|
+
|
|
66
|
+
- Create or update architecture diagrams in `docs/`
|
|
67
|
+
- Explain the decision and alternatives considered
|
|
68
|
+
- Link back to the discussion/issue where the change was planned
|
|
69
|
+
|
|
70
|
+
### Error Handling
|
|
71
|
+
|
|
72
|
+
If you add new error handling:
|
|
73
|
+
|
|
74
|
+
- Document each error with resolution steps
|
|
75
|
+
- Steps must be followable by anyone regardless of skill level
|
|
76
|
+
- Include the error message, cause, and fix
|
|
77
|
+
|
|
78
|
+
### API Documentation
|
|
79
|
+
|
|
80
|
+
If you add exported functions, endpoints, or tool definitions:
|
|
81
|
+
|
|
82
|
+
- Document parameters, return shapes, and error behavior
|
|
83
|
+
- Update the package README
|
|
84
|
+
|
|
85
|
+
## Lore Maintenance
|
|
86
|
+
|
|
87
|
+
- When decisions change, update the relevant docs
|
|
88
|
+
- Link docs to the discussion/issue where the decision was made
|
|
89
|
+
- Use `loreli tools context --action search` to find existing docs before creating new ones
|