loreli 1.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/README.md +66 -26
- package/package.json +17 -14
- package/packages/action/prompts/action.md +172 -0
- package/packages/action/src/index.js +33 -5
- package/packages/agent/README.md +107 -18
- package/packages/agent/src/backends/claude.js +111 -11
- package/packages/agent/src/backends/codex.js +78 -5
- package/packages/agent/src/backends/cursor.js +104 -27
- package/packages/agent/src/backends/index.js +162 -5
- package/packages/agent/src/cli.js +80 -3
- package/packages/agent/src/discover.js +396 -0
- package/packages/agent/src/factory.js +39 -34
- package/packages/agent/src/models.js +24 -6
- 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 +156 -91
- package/packages/config/src/defaults.js +32 -21
- package/packages/config/src/index.js +33 -2
- package/packages/config/src/schema.js +57 -39
- package/packages/hub/src/github.js +59 -20
- package/packages/identity/README.md +1 -1
- package/packages/identity/src/index.js +2 -2
- package/packages/knowledge/README.md +86 -106
- package/packages/knowledge/src/index.js +56 -225
- package/packages/mcp/README.md +51 -7
- package/packages/mcp/instructions.md +6 -1
- package/packages/mcp/scaffolding/loreli.yml +115 -77
- package/packages/mcp/scaffolding/mcp-configs/.codex/config.toml +1 -0
- package/packages/mcp/scaffolding/mcp-configs/.cursor/mcp.json +4 -1
- package/packages/mcp/scaffolding/mcp-configs/.mcp.json +4 -1
- package/packages/mcp/src/index.js +45 -16
- package/packages/mcp/src/tools/agent-context.js +44 -0
- package/packages/mcp/src/tools/agents.js +34 -13
- package/packages/mcp/src/tools/context.js +3 -2
- package/packages/mcp/src/tools/github.js +11 -47
- package/packages/mcp/src/tools/hitl.js +19 -6
- package/packages/mcp/src/tools/index.js +2 -1
- 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 +159 -90
- package/packages/mcp/src/tools/status.js +5 -2
- package/packages/mcp/src/tools/work.js +18 -8
- package/packages/orchestrator/src/index.js +345 -79
- package/packages/planner/README.md +84 -1
- 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 +326 -111
- package/packages/review/README.md +2 -2
- package/packages/review/prompts/reviewer.md +158 -0
- package/packages/review/src/index.js +196 -76
- package/packages/risk/README.md +81 -22
- package/packages/risk/prompts/risk.md +272 -0
- package/packages/risk/src/index.js +44 -33
- package/packages/tmux/src/index.js +61 -12
- package/packages/workflow/README.md +18 -14
- package/packages/workflow/prompts/preamble.md +14 -0
- package/packages/workflow/src/index.js +191 -12
- package/packages/workspace/README.md +2 -2
- package/packages/workspace/src/index.js +69 -18
package/packages/mcp/README.md
CHANGED
|
@@ -15,6 +15,8 @@ Before using the CLI tool commands below, configure an MCP server entry named `l
|
|
|
15
15
|
```bash
|
|
16
16
|
loreli tools list
|
|
17
17
|
loreli tools start --repo owner/repo
|
|
18
|
+
# or rely on repo fallback from loreli.yml / LORELI_REPO
|
|
19
|
+
loreli tools start
|
|
18
20
|
loreli tools team_status
|
|
19
21
|
loreli tools agents --action check
|
|
20
22
|
```
|
|
@@ -58,7 +60,7 @@ All tools are visible at all times. No progressive disclosure — every tool is
|
|
|
58
60
|
|
|
59
61
|
| Tool | Description |
|
|
60
62
|
|------|-------------|
|
|
61
|
-
| `start` | Initialize orchestration for a target GitHub repo. Validates access, discovers/scaffolds templates, creates project board. Idempotent — safe to re-run. |
|
|
63
|
+
| `start` | Initialize orchestration for a target GitHub repo. Accepts `--repo`, or falls back to configured `repo` from `loreli.yml` / `LORELI_REPO`. Validates access, discovers/scaffolds templates, creates project board. Idempotent — safe to re-run. |
|
|
62
64
|
| `environment` | Report detected environment: tmux, backends, providers, review strategy. |
|
|
63
65
|
|
|
64
66
|
### Team Management
|
|
@@ -67,17 +69,59 @@ All tools are visible at all times. No progressive disclosure — every tool is
|
|
|
67
69
|
|------|-------------|
|
|
68
70
|
| `add_agent` | Add an agent. Params: `provider` (`openai`, `anthropic`, `cursor-openai`, `cursor-anthropic`), `role` (`planner`, `action`, `reviewer`), `model`, `theme`. |
|
|
69
71
|
| `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
|
-
|
|
72
|
+
| `start_planning` | Activate planner agents to analyze the repo and create draft work items. Accepts an `objective` to guide the planner. Uses explicit `repo` argument when provided, otherwise falls back to configured `repo`. |
|
|
73
|
+
| `start_work` | Begin action/review cycle. Action agents claim issues, do work, create PRs. Review agents are auto-assigned via yin/yang pairing. Uses explicit `repo` argument when provided, otherwise falls back to configured `repo`. |
|
|
74
|
+
| `team_status` | Dashboard: issues, PRs, agent states with terminal snapshots (last 20 lines), review loops, PRs awaiting human review, and GitHub API rate limits. Uses explicit `repo` argument when provided, otherwise falls back to configured `repo`. |
|
|
75
|
+
|
|
76
|
+
### Agent Tools (Agent-Only)
|
|
77
|
+
|
|
78
|
+
| Tool | Description |
|
|
79
|
+
|------|-------------|
|
|
80
|
+
| `plan` | Plan lifecycle management. Actions: `create` (new discussion), `revise` (update after feedback), `verdict` (approve/reject as reviewer), `escalate` (flag process or architecture concerns). |
|
|
81
|
+
| `pr` | Pull request lifecycle. Actions: `create` (open PR from branch), `review` (submit adversarial review). |
|
|
82
|
+
| `comment` | Post a comment on the agent's current work item. Set `claim: true` to claim an issue, `abandon: true` to abandon. |
|
|
83
|
+
| `read` | Read any issue, PR, or discussion by number. |
|
|
84
|
+
| `refactor` | Flag a bug, code smell, or tech debt discovered during implementation. Action agents only. Creates a deduplicated Loreli discussion labeled `loreli:refactor` that enters the standard review/promote pipeline. |
|
|
85
|
+
| `context` | Resolve code context. Actions: `blame`, `history`, `search`, `patterns`. |
|
|
86
|
+
| `environment` | Report detected environment: tmux, backends, providers, review strategy. |
|
|
87
|
+
|
|
88
|
+
#### `refactor` Tool
|
|
89
|
+
|
|
90
|
+
Enables [opportunistic refactoring](https://martinfowler.com/bliki/OpportunisticRefactoring.html) — action agents report improvements they discover without leaving their assigned scope.
|
|
91
|
+
|
|
92
|
+
**Parameters:**
|
|
93
|
+
|
|
94
|
+
| Parameter | Type | Required | Description |
|
|
95
|
+
|-----------|------|----------|-------------|
|
|
96
|
+
| `kind` | `string` | yes | Category: `bug`, `refactor`, `smell`, or `debt` |
|
|
97
|
+
| `title` | `string` | yes | Concise improvement title |
|
|
98
|
+
| `description` | `string` | yes | Problem statement with stable identifiers (function names, class names, error messages) |
|
|
99
|
+
| `files` | `string[]` | no | Affected file paths, optionally with line range hints |
|
|
100
|
+
| `impact` | `string` | no | `low`, `medium` (default), or `high` |
|
|
101
|
+
|
|
102
|
+
**File path format:**
|
|
103
|
+
|
|
104
|
+
File entries accept plain paths or paths with GitHub-style line range hints:
|
|
105
|
+
|
|
106
|
+
- `src/hub.js` — plain path
|
|
107
|
+
- `packages/hub/src/github.js#R40-R50` — path with line range hint (lines 40–50)
|
|
108
|
+
|
|
109
|
+
Line ranges are advisory hints; they may drift between commits. Always include stable identifiers (function names, error patterns) in the `description`.
|
|
110
|
+
|
|
111
|
+
**Dedup behavior:**
|
|
112
|
+
|
|
113
|
+
Before creating a discussion, the tool searches existing issues and `loreli:refactor`-labeled discussions by normalized title. If a match is found, it returns an "Already tracked" reference instead of creating a duplicate. Dedup is best-effort — parallel reports can race.
|
|
114
|
+
|
|
115
|
+
**Pipeline integration:**
|
|
116
|
+
|
|
117
|
+
Created discussions enter the existing planner review/revise/promote pipeline. When promoted to issues, the `loreli:refactor` label is carried to the new issue for tracking.
|
|
74
118
|
|
|
75
119
|
### Human In The Loop (HITL)
|
|
76
120
|
|
|
77
121
|
| Tool | Description |
|
|
78
122
|
|------|-------------|
|
|
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. |
|
|
123
|
+
| `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. Uses explicit `repo` argument when provided, otherwise falls back to configured `repo`. |
|
|
124
|
+
| `watch` | Check an HITL PR for new human feedback. Filters out agent comments. Returns comments posted after the HITL timestamp. Uses explicit `repo` argument when provided, otherwise falls back to configured `repo`. |
|
|
81
125
|
|
|
82
126
|
### Agent Lifecycle
|
|
83
127
|
|
|
@@ -67,7 +67,10 @@ When you are a spawned agent (planner, action, or reviewer), use the Loreli MCP
|
|
|
67
67
|
| **plan** | `create`, `revise`, `verdict`, `escalate` | Planner creates/revises; Reviewer renders verdict; Any role escalates |
|
|
68
68
|
| **pr** | `create`, `review` | Action creates PRs; Reviewer submits reviews |
|
|
69
69
|
| **comment** | (none) | Any role posts comments on their current work item |
|
|
70
|
+
| **read** | (none) | Any role reads issues, PRs, or discussions by number |
|
|
71
|
+
| **refactor** | (none) | Action flags bugs, smells, debt for planning |
|
|
70
72
|
| **context** | `blame`, `history`, `search`, `patterns` | Any role looks up code context, decision history, and feedback patterns |
|
|
73
|
+
| **environment** | (none) | Any role checks available backends |
|
|
71
74
|
|
|
72
75
|
### Context Resolution
|
|
73
76
|
|
|
@@ -89,8 +92,9 @@ Tools enforce role boundaries server-side:
|
|
|
89
92
|
| `plan/verdict` | reviewer | planner, action |
|
|
90
93
|
| `pr/create` | action | planner, reviewer |
|
|
91
94
|
| `pr/review` | reviewer | planner, action |
|
|
95
|
+
| `refactor` | action | planner, reviewer |
|
|
92
96
|
| `plan/escalate`, `comment` | any | — |
|
|
93
|
-
| `context
|
|
97
|
+
| `context/*`, `read`, `environment` | any | — |
|
|
94
98
|
|
|
95
99
|
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
100
|
|
|
@@ -117,5 +121,6 @@ Also available via CLI: `loreli tools context --action blame --file <path> --lin
|
|
|
117
121
|
4. **Respect your role**: Only use actions permitted for your role. Attempting unauthorized actions wastes tokens and time.
|
|
118
122
|
5. **Honor repository policy files**: If `AGENTS.md` exists in the repository root, treat it as authoritative repository policy input.
|
|
119
123
|
6. **Follow role prompt quality gates**: Testing and style-quality requirements are enforced in role-specific prompts and review flows; do not bypass them.
|
|
124
|
+
7. **Flag improvements opportunistically**: When you encounter bugs, code smells, or tech debt during your work, use the `refactor` tool immediately. Do not fix out-of-scope issues yourself — flag them and continue your task. The dedup gate prevents duplicate reports. Use `plan` (action: `escalate`) for process or architecture concerns, not code-level findings.
|
|
120
125
|
|
|
121
126
|
</rules>
|
|
@@ -24,6 +24,13 @@ theme: transformers # string or list: transformers | pokemon | marvel |
|
|
|
24
24
|
# Change when: You want a global quality/cost baseline shift for all agents.
|
|
25
25
|
model: balanced # fast | balanced | powerful | exact model string
|
|
26
26
|
|
|
27
|
+
# repo
|
|
28
|
+
# What: Optional repository slug fallback for standalone tool contexts before start runs.
|
|
29
|
+
# Impact: Enables tools like `loreli tools context`, `start_work`, and `hitl` to resolve repository scope without session hydration.
|
|
30
|
+
# Signal: CLI tools report "No repository configured" outside agent/start sessions.
|
|
31
|
+
# Change when: You regularly run Loreli tools directly from a shell and want a persistent repo default.
|
|
32
|
+
# repo: owner/repo
|
|
33
|
+
|
|
27
34
|
# --- Merge gate ---
|
|
28
35
|
# reviewers
|
|
29
36
|
# What: GitHub usernames for HITL review requests.
|
|
@@ -114,6 +121,14 @@ timeouts:
|
|
|
114
121
|
# Change when: Startup failures are missed (increase) or false positives occur (decrease).
|
|
115
122
|
rapidDeath: 15s
|
|
116
123
|
|
|
124
|
+
# timeouts.proxyDiscovery
|
|
125
|
+
# What: HTTP timeout for proxy model discovery calls used by claude/codex.
|
|
126
|
+
# Impact: Lower values fail fast on unhealthy proxies; higher values tolerate slower proxy endpoints.
|
|
127
|
+
# Signal: Discovery frequently times out on healthy but slow networks (increase),
|
|
128
|
+
# or startup blocks too long on unreachable proxy endpoints (decrease).
|
|
129
|
+
# Change when: Proxy-backed environments need slower/faster discovery behavior.
|
|
130
|
+
proxyDiscovery: 5s
|
|
131
|
+
|
|
117
132
|
# timeouts.nudge
|
|
118
133
|
# What: Enables/disables tier-1 "you appear stalled" message.
|
|
119
134
|
# Impact: true may interrupt deep work; false keeps escalation signals without message interruption.
|
|
@@ -144,15 +159,6 @@ watch:
|
|
|
144
159
|
# Change when: Agents are underutilized (increase) or overloaded (decrease).
|
|
145
160
|
maxClaims: 3
|
|
146
161
|
|
|
147
|
-
# --- Review policy ---
|
|
148
|
-
review:
|
|
149
|
-
# review.skipRiskAssessment
|
|
150
|
-
# What: Skips mandatory risk verdict checks in review flow.
|
|
151
|
-
# Impact: Faster review path with less explicit risk gating.
|
|
152
|
-
# Signal: Teams intentionally bypassing risk gates for speed, or conversely incidents from insufficient risk checks (set false).
|
|
153
|
-
# Change when: You intentionally prefer speed over formal risk signoff.
|
|
154
|
-
skipRiskAssessment: false
|
|
155
|
-
|
|
156
162
|
# --- Scaling policy ---
|
|
157
163
|
scaling:
|
|
158
164
|
# scaling.maxAgents
|
|
@@ -162,35 +168,6 @@ scaling:
|
|
|
162
168
|
# Change when: You need more throughput (increase) or tighter resource limits (decrease).
|
|
163
169
|
maxAgents: 8
|
|
164
170
|
|
|
165
|
-
maxPerRole:
|
|
166
|
-
# scaling.maxPerRole.action
|
|
167
|
-
# What: Max concurrent action agents.
|
|
168
|
-
# Impact: Controls parallel implementation throughput.
|
|
169
|
-
# Signal: Large implementation queue with insufficient coding capacity.
|
|
170
|
-
# Change when: Work backlog is implementation-heavy.
|
|
171
|
-
action: 3
|
|
172
|
-
|
|
173
|
-
# scaling.maxPerRole.reviewer
|
|
174
|
-
# What: Max concurrent reviewer agents.
|
|
175
|
-
# Impact: Controls review bottleneck relief.
|
|
176
|
-
# Signal: PRs are ready but waiting on reviewer assignment/completion.
|
|
177
|
-
# Change when: PR queue waits on reviews.
|
|
178
|
-
reviewer: 2
|
|
179
|
-
|
|
180
|
-
# scaling.maxPerRole.risk
|
|
181
|
-
# What: Max concurrent risk agents.
|
|
182
|
-
# Impact: Controls parallel risk assessment capacity.
|
|
183
|
-
# Signal: Reviews blocked on risk verdicts.
|
|
184
|
-
# Change when: Risk checks become the bottleneck.
|
|
185
|
-
risk: 3
|
|
186
|
-
|
|
187
|
-
# scaling.maxPerRole.planner
|
|
188
|
-
# What: Max concurrent planner agents.
|
|
189
|
-
# Impact: Limits parallel planning/discussion churn.
|
|
190
|
-
# Signal: Planning queue grows (increase) or discussion noise overwhelms maintainers (decrease).
|
|
191
|
-
# Change when: You want more/fewer simultaneous planning threads.
|
|
192
|
-
planner: 1
|
|
193
|
-
|
|
194
171
|
# scaling.maxPerTick
|
|
195
172
|
# What: Spawn budget per reactor tick.
|
|
196
173
|
# Impact: Higher values ramp up faster but can spike load.
|
|
@@ -301,6 +278,36 @@ agents:
|
|
|
301
278
|
# anthropic: opus-4.6-thinking
|
|
302
279
|
# openai: gpt-5.1-codex-max
|
|
303
280
|
|
|
281
|
+
# --- Classification ---
|
|
282
|
+
classify:
|
|
283
|
+
# classify.model
|
|
284
|
+
# What: Model tier used for non-interactive classification prompts.
|
|
285
|
+
# Impact: Higher tiers may classify more accurately but cost more and respond slower.
|
|
286
|
+
# Signal: Misclassified pane states/feedback or excessive latency/cost.
|
|
287
|
+
# Change when: You want a different speed/accuracy trade-off for classification tasks.
|
|
288
|
+
model: fast
|
|
289
|
+
|
|
290
|
+
# classify.maxLines
|
|
291
|
+
# What: Max pane lines captured for classifier input.
|
|
292
|
+
# Impact: Higher values provide more context but increase token usage and prompt size.
|
|
293
|
+
# Signal: Classifier misses important terminal context (increase), or prompts are noisy/too large (decrease).
|
|
294
|
+
# Change when: Terminal-state classification needs more or less surrounding context.
|
|
295
|
+
maxLines: 100
|
|
296
|
+
|
|
297
|
+
# classify.timeout
|
|
298
|
+
# What: Timeout for non-interactive classifier calls.
|
|
299
|
+
# Impact: Higher values tolerate cold starts; lower values fail fast on stuck backends.
|
|
300
|
+
# Signal: Frequent classifier timeouts on healthy backends (increase), or long stalls waiting for dead ones (decrease).
|
|
301
|
+
# Change when: Your classifier backends are slower or faster than the default.
|
|
302
|
+
timeout: 30s
|
|
303
|
+
|
|
304
|
+
# classify.maxRetries
|
|
305
|
+
# What: Max consecutive classifier failures before the orchestrator gives up and escalates.
|
|
306
|
+
# Impact: Higher values are more tolerant of transient failures; lower values fail closed sooner.
|
|
307
|
+
# Signal: Temporary classifier hiccups cause unnecessary kills/escalations (increase), or repeated failures waste time (decrease).
|
|
308
|
+
# Change when: You need a stricter or more forgiving classifier failure budget.
|
|
309
|
+
maxRetries: 5
|
|
310
|
+
|
|
304
311
|
# --- Trace capture ---
|
|
305
312
|
trace:
|
|
306
313
|
# trace.enabled
|
|
@@ -324,34 +331,6 @@ trace:
|
|
|
324
331
|
# Change when: Useful context is being truncated too aggressively.
|
|
325
332
|
maxOutputChars: 8000
|
|
326
333
|
|
|
327
|
-
workflows:
|
|
328
|
-
planner:
|
|
329
|
-
# trace.workflows.planner.enabled / maxOutputChars
|
|
330
|
-
# What: Planner-specific trace override.
|
|
331
|
-
# Impact: Fine-grained planner trace tuning.
|
|
332
|
-
# Signal: Planner traces need different verbosity than global behavior.
|
|
333
|
-
# Change when: Planner traces need different verbosity than global default.
|
|
334
|
-
enabled: true
|
|
335
|
-
maxOutputChars: 4000
|
|
336
|
-
|
|
337
|
-
reviewer:
|
|
338
|
-
# trace.workflows.reviewer.enabled / maxOutputChars
|
|
339
|
-
# What: Reviewer-specific trace override.
|
|
340
|
-
# Impact: Fine-grained reviewer trace tuning.
|
|
341
|
-
# Signal: Reviewer traces are too sparse for diagnosis or too noisy for signal extraction.
|
|
342
|
-
# Change when: Reviewer traces are too noisy or too sparse.
|
|
343
|
-
enabled: true
|
|
344
|
-
maxOutputChars: 4000
|
|
345
|
-
|
|
346
|
-
risk:
|
|
347
|
-
# trace.workflows.risk.enabled / maxOutputChars
|
|
348
|
-
# What: Risk-specific trace override.
|
|
349
|
-
# Impact: Fine-grained risk trace tuning.
|
|
350
|
-
# Signal: Risk reasoning context is truncated (increase) or over-captured (decrease).
|
|
351
|
-
# Change when: Risk traces need tighter/looser capture bounds.
|
|
352
|
-
enabled: true
|
|
353
|
-
maxOutputChars: 2000
|
|
354
|
-
|
|
355
334
|
# --- Proof of life ---
|
|
356
335
|
proofOfLife:
|
|
357
336
|
# proofOfLife.timeout
|
|
@@ -386,17 +365,69 @@ cleanup:
|
|
|
386
365
|
# Change when: You want explicit/manual cleanup control (set false).
|
|
387
366
|
autoprune: true
|
|
388
367
|
|
|
389
|
-
# ---
|
|
390
|
-
#
|
|
391
|
-
# What:
|
|
392
|
-
# Impact:
|
|
393
|
-
# Signal:
|
|
394
|
-
# Change when: You
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
#
|
|
398
|
-
#
|
|
399
|
-
#
|
|
368
|
+
# --- Per-workflow configuration ---
|
|
369
|
+
# workflows.{role}
|
|
370
|
+
# What: Per-role settings consolidating model tier, agent cap, prompt override, trace, and skip flags.
|
|
371
|
+
# Impact: Each workflow role can be tuned independently — model quality, parallelism, and observability.
|
|
372
|
+
# Signal: Different roles need different cost/quality trade-offs, scaling limits, or trace verbosity.
|
|
373
|
+
# Change when: You want per-role model tiers, scaling, custom prompts, or trace settings.
|
|
374
|
+
workflows:
|
|
375
|
+
action:
|
|
376
|
+
# workflows.action.model
|
|
377
|
+
# What: Model tier for action agents (implementation work).
|
|
378
|
+
# Impact: Controls quality/cost of code generation.
|
|
379
|
+
# Change when: You want stronger/cheaper implementation agents.
|
|
380
|
+
model: balanced
|
|
381
|
+
|
|
382
|
+
# workflows.action.maxAgents
|
|
383
|
+
# What: Max concurrent action agents.
|
|
384
|
+
# Impact: Controls parallel implementation throughput.
|
|
385
|
+
# Change when: Work backlog is implementation-heavy.
|
|
386
|
+
maxAgents: 3
|
|
387
|
+
|
|
388
|
+
# workflows.action.prompt
|
|
389
|
+
# What: Repo-local prompt file override for action agents.
|
|
390
|
+
# Impact: Changes agent instructions without code changes.
|
|
391
|
+
# Change when: You need project-specific coding guardrails.
|
|
392
|
+
# prompt: .loreli/action.md
|
|
393
|
+
|
|
394
|
+
reviewer:
|
|
395
|
+
# workflows.reviewer.model
|
|
396
|
+
# What: Model tier for reviewer agents.
|
|
397
|
+
# Change when: You want stronger/cheaper review agents.
|
|
398
|
+
model: balanced
|
|
399
|
+
maxAgents: 2
|
|
400
|
+
# prompt: .loreli/reviewer.md
|
|
401
|
+
trace:
|
|
402
|
+
enabled: true
|
|
403
|
+
maxOutputChars: 4000
|
|
404
|
+
|
|
405
|
+
risk:
|
|
406
|
+
# workflows.risk.model
|
|
407
|
+
# What: Model tier for risk assessment agents.
|
|
408
|
+
# Change when: Risk evaluation needs deeper reasoning (powerful) or is fine with fast triage (fast).
|
|
409
|
+
model: fast
|
|
410
|
+
maxAgents: 3
|
|
411
|
+
|
|
412
|
+
# workflows.risk.skip
|
|
413
|
+
# What: Skips mandatory risk verdict checks in review flow.
|
|
414
|
+
# Impact: Faster review path with less explicit risk gating.
|
|
415
|
+
# Change when: You intentionally prefer speed over formal risk signoff.
|
|
416
|
+
skip: false
|
|
417
|
+
trace:
|
|
418
|
+
enabled: true
|
|
419
|
+
maxOutputChars: 2000
|
|
420
|
+
|
|
421
|
+
planner:
|
|
422
|
+
# workflows.planner.model
|
|
423
|
+
# What: Model tier for planner agents.
|
|
424
|
+
# Change when: Planning quality needs deeper reasoning.
|
|
425
|
+
model: powerful
|
|
426
|
+
maxAgents: 1
|
|
427
|
+
# prompt: .loreli/planner.md
|
|
428
|
+
trace:
|
|
429
|
+
enabled: true
|
|
430
|
+
maxOutputChars: 4000
|
|
400
431
|
|
|
401
432
|
# --- Feedback and knowledge capture ---
|
|
402
433
|
feedback:
|
|
@@ -427,6 +458,13 @@ feedback:
|
|
|
427
458
|
- performance
|
|
428
459
|
- security
|
|
429
460
|
|
|
461
|
+
# feedback.hitl
|
|
462
|
+
# What: Controls Human In The Loop escalation for feedback-driven PRs at merge time.
|
|
463
|
+
# Impact: true gates all feedback PRs on human approval; false allows full automation; array gates only listed categories.
|
|
464
|
+
# Signal: Feedback-driven changes landing without review (set true or list categories), or unnecessary merge friction (set false).
|
|
465
|
+
# Change when: You want human oversight on specific feedback categories (e.g. architecture, security) while letting others auto-merge.
|
|
466
|
+
hitl: false
|
|
467
|
+
|
|
430
468
|
# --- Tmux ---
|
|
431
469
|
tmux:
|
|
432
470
|
# tmux.session
|
|
@@ -20,6 +20,7 @@ import { PlannerWorkflow } from 'loreli/planner';
|
|
|
20
20
|
import { ActionWorkflow } from 'loreli/action';
|
|
21
21
|
import { RiskWorkflow } from 'loreli/risk';
|
|
22
22
|
import { ReviewWorkflow } from 'loreli/review';
|
|
23
|
+
import { Config } from 'loreli/config';
|
|
23
24
|
import { logger } from 'loreli/log';
|
|
24
25
|
|
|
25
26
|
const log = logger('mcp');
|
|
@@ -41,12 +42,18 @@ const EMPTY_SCHEMA = { type: 'object', properties: {} };
|
|
|
41
42
|
* start_work. Exposing those tools leads to confused agents calling
|
|
42
43
|
* them, which destroys workspaces and starts duplicate reactor loops.
|
|
43
44
|
*
|
|
44
|
-
* `start`
|
|
45
|
-
* ("already configured") instead of an error.
|
|
45
|
+
* `start` was previously included so agents would receive a no-op
|
|
46
|
+
* response ("already configured") instead of an error. However, when
|
|
47
|
+
* agent hydration fails or env vars are missing, the no-op guard
|
|
48
|
+
* (`ctx.sessionId && ctx.agentName`) doesn't fire and the call falls
|
|
49
|
+
* through to the real implementation — which reaps the tmux session,
|
|
50
|
+
* killing every running agent. Observed in E2E: a Cursor Agent called
|
|
51
|
+
* `start` on its own repo, destroying the session it was living in.
|
|
52
|
+
* Safer to block it entirely and return a clean "not available" error.
|
|
46
53
|
*
|
|
47
54
|
* @type {Set<string>}
|
|
48
55
|
*/
|
|
49
|
-
const AGENT_TOOLS = new Set(['plan', 'pr', 'comment', 'read', 'environment', 'context', '
|
|
56
|
+
const AGENT_TOOLS = new Set(['plan', 'pr', 'comment', 'read', 'environment', 'context', 'refactor']);
|
|
50
57
|
|
|
51
58
|
/**
|
|
52
59
|
* Loreli MCP server for agentic team orchestration.
|
|
@@ -182,7 +189,7 @@ export class Loreli {
|
|
|
182
189
|
if (ctx.agentName && !AGENT_TOOLS.has(name)) {
|
|
183
190
|
log.warn(`agent ${ctx.agentName} blocked from calling host tool: ${name}`);
|
|
184
191
|
return {
|
|
185
|
-
content: [{ type: 'text', text: `Tool "${name}" is not available to agents. Use plan, pr, comment, or
|
|
192
|
+
content: [{ type: 'text', text: `Tool "${name}" is not available to agents. Use plan, pr, comment, read, refactor, environment, or context.` }],
|
|
186
193
|
isError: true
|
|
187
194
|
};
|
|
188
195
|
}
|
|
@@ -283,11 +290,16 @@ export class Loreli {
|
|
|
283
290
|
*/
|
|
284
291
|
async _prepare() {
|
|
285
292
|
const home = this.config.home ?? process.env.LORELI_HOME ?? join(homedir(), '.loreli');
|
|
293
|
+
const config = new Config();
|
|
294
|
+
config.loadLocal('loreli.yml');
|
|
295
|
+
config.merge(this.config);
|
|
296
|
+
|
|
286
297
|
const identityRegistry = new Registry();
|
|
287
298
|
const backendRegistry = new BackendRegistry();
|
|
288
299
|
const storage = new Storage({ home });
|
|
289
300
|
|
|
290
301
|
const orchestrator = new Orchestrator({ hub: null, identityRegistry, backendRegistry, storage });
|
|
302
|
+
orchestrator.cfg = config;
|
|
291
303
|
|
|
292
304
|
this.ctx = {
|
|
293
305
|
hub: null,
|
|
@@ -302,8 +314,8 @@ export class Loreli {
|
|
|
302
314
|
clientIdentity: null,
|
|
303
315
|
clientName: null,
|
|
304
316
|
clientVersion: null,
|
|
305
|
-
config
|
|
306
|
-
repo: null,
|
|
317
|
+
config,
|
|
318
|
+
repo: config.get('repo') ?? null,
|
|
307
319
|
categoryId: null,
|
|
308
320
|
sessionId: null,
|
|
309
321
|
server: this
|
|
@@ -354,7 +366,7 @@ export class Loreli {
|
|
|
354
366
|
|
|
355
367
|
const data = await storage.load(sessionId, agentName);
|
|
356
368
|
if (data) {
|
|
357
|
-
this.ctx.repo = data.repo ?? process.env.LORELI_REPO ?? null;
|
|
369
|
+
this.ctx.repo = data.repo ?? process.env.LORELI_REPO ?? this.ctx.repo ?? null;
|
|
358
370
|
if (data.identity) {
|
|
359
371
|
// Identity.toJSON() stores `name` as full name and `character`
|
|
360
372
|
// as the raw character. The constructor expects `name` = character.
|
|
@@ -371,7 +383,7 @@ export class Loreli {
|
|
|
371
383
|
log.info(`agent context hydrated: ${agentName} (session: ${sessionId}, repo: ${this.ctx.repo})`);
|
|
372
384
|
} else {
|
|
373
385
|
// Fallback to env var when storage has no data yet (first startup)
|
|
374
|
-
this.ctx.repo = process.env.LORELI_REPO ?? null;
|
|
386
|
+
this.ctx.repo = process.env.LORELI_REPO ?? this.ctx.repo ?? null;
|
|
375
387
|
log.warn(`agent session data not found for ${agentName} in ${sessionId}, using env fallback`);
|
|
376
388
|
}
|
|
377
389
|
|
|
@@ -397,9 +409,9 @@ export class Loreli {
|
|
|
397
409
|
async _hydrateHub() {
|
|
398
410
|
let token = process.env.GITHUB_TOKEN;
|
|
399
411
|
|
|
400
|
-
//
|
|
401
|
-
//
|
|
402
|
-
//
|
|
412
|
+
// Keep a file-based fallback for startup paths where the host did
|
|
413
|
+
// not provide GITHUB_TOKEN to this process. create() writes
|
|
414
|
+
// .git/loreli.env inside .git/ (inherently unstageable by git).
|
|
403
415
|
if (!token) {
|
|
404
416
|
try {
|
|
405
417
|
const { readFileSync } = await import('node:fs');
|
|
@@ -434,9 +446,10 @@ export class Loreli {
|
|
|
434
446
|
// Load config from loreli.yml when repo is known
|
|
435
447
|
if (this.ctx.repo && this.ctx.hub) {
|
|
436
448
|
try {
|
|
437
|
-
const { Config } = await import('loreli/config');
|
|
438
449
|
const config = new Config();
|
|
450
|
+
config.merge(this.config);
|
|
439
451
|
await config.load(this.ctx.hub, this.ctx.repo);
|
|
452
|
+
config.merge(this.config);
|
|
440
453
|
this.ctx.config = config;
|
|
441
454
|
this.ctx.orchestrator.cfg = config;
|
|
442
455
|
log.info(`agent config loaded from ${this.ctx.repo}/loreli.yml`);
|
|
@@ -523,12 +536,19 @@ export class Loreli {
|
|
|
523
536
|
// stub would treat every pane in the session as orphaned and kill
|
|
524
537
|
// all sibling agents. Only the host process owns the real registry.
|
|
525
538
|
const self = this;
|
|
526
|
-
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* @param {'SIGINT'|'SIGTERM'|'transport-close'} reason - What triggered shutdown.
|
|
542
|
+
*/
|
|
543
|
+
async function gracefulExit(reason) {
|
|
527
544
|
if (self.ctx?.agentName) {
|
|
545
|
+
log.info(`agent ${self.ctx.agentName} MCP server exiting (${reason})`);
|
|
528
546
|
process.exit(0);
|
|
529
547
|
return;
|
|
530
548
|
}
|
|
531
549
|
|
|
550
|
+
log.info(`host MCP server exiting (${reason})`);
|
|
551
|
+
|
|
532
552
|
self.ctx?.orchestrator?.unwatch?.();
|
|
533
553
|
self.ctx?.orchestrator?.stopMonitor?.();
|
|
534
554
|
|
|
@@ -553,16 +573,25 @@ export class Loreli {
|
|
|
553
573
|
process.exit(0);
|
|
554
574
|
}
|
|
555
575
|
|
|
556
|
-
process.on('SIGINT', gracefulExit);
|
|
557
|
-
process.on('SIGTERM', gracefulExit);
|
|
576
|
+
process.on('SIGINT', function onSigint() { gracefulExit('SIGINT'); });
|
|
577
|
+
process.on('SIGTERM', function onSigterm() { gracefulExit('SIGTERM'); });
|
|
558
578
|
|
|
559
579
|
log.info('loreli MCP server starting');
|
|
580
|
+
|
|
581
|
+
transport.onerror = function onTransportError(err) {
|
|
582
|
+
log.error(`MCP transport error: ${err?.message ?? err}`);
|
|
583
|
+
};
|
|
584
|
+
|
|
560
585
|
await this.server.connect(transport);
|
|
561
586
|
|
|
587
|
+
this.server.onerror = function onServerError(err) {
|
|
588
|
+
log.error(`MCP server error: ${err?.message ?? err}`);
|
|
589
|
+
};
|
|
590
|
+
|
|
562
591
|
// Transport disconnect (client closed pipe, host exited) bypasses
|
|
563
592
|
// process signals entirely. Wire the SDK's onclose so cleanup runs
|
|
564
593
|
// regardless of how the connection ends.
|
|
565
|
-
this.server.onclose = gracefulExit;
|
|
594
|
+
this.server.onclose = function onTransportClose() { gracefulExit('transport-close'); };
|
|
566
595
|
|
|
567
596
|
log.info('loreli MCP server connected');
|
|
568
597
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Identity } from 'loreli/identity';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolve agent context from session storage.
|
|
5
|
+
*
|
|
6
|
+
* Reads the agent's persisted session data using the sessionId and
|
|
7
|
+
* agentName from ctx (hydrated at MCP server startup from env vars).
|
|
8
|
+
* Reconstructs a live Identity instance so hub stamping and label
|
|
9
|
+
* methods work correctly. Throws when context is not available — this
|
|
10
|
+
* means the tool was called from a non-agent MCP client.
|
|
11
|
+
*
|
|
12
|
+
* @param {object} ctx - Execution context with sessionId, agentName, storage.
|
|
13
|
+
* @returns {Promise<{repo: string, identity: Identity, role: string, task: object|null, issue: number|null, paneId: string|null}>}
|
|
14
|
+
* @throws {Error} When agent context is not available.
|
|
15
|
+
*/
|
|
16
|
+
export async function context(ctx) {
|
|
17
|
+
if (!ctx.sessionId || !ctx.agentName) {
|
|
18
|
+
throw new Error('Agent context not available. This tool can only be called by spawned agents.');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const data = await ctx.storage.load(ctx.sessionId, ctx.agentName);
|
|
22
|
+
if (!data) {
|
|
23
|
+
throw new Error(`Session data not found for agent "${ctx.agentName}" in session "${ctx.sessionId}".`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const raw = data.identity;
|
|
27
|
+
const identity = new Identity({
|
|
28
|
+
name: raw.character ?? raw.name,
|
|
29
|
+
instance: raw.instance ?? 0,
|
|
30
|
+
faction: raw.faction,
|
|
31
|
+
provider: raw.provider,
|
|
32
|
+
model: raw.model,
|
|
33
|
+
theme: raw.theme
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
repo: data.repo,
|
|
38
|
+
identity,
|
|
39
|
+
role: data.role,
|
|
40
|
+
task: data.task ?? null,
|
|
41
|
+
issue: data.claimedIssue ?? data.task?.issue ?? null,
|
|
42
|
+
paneId: data.paneId ?? null
|
|
43
|
+
};
|
|
44
|
+
}
|