loreli 0.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +710 -97
  3. package/bin/loreli.js +89 -0
  4. package/package.json +77 -14
  5. package/packages/README.md +101 -0
  6. package/packages/action/README.md +98 -0
  7. package/packages/action/prompts/action.md +172 -0
  8. package/packages/action/src/index.js +684 -0
  9. package/packages/agent/README.md +606 -0
  10. package/packages/agent/src/backends/claude.js +387 -0
  11. package/packages/agent/src/backends/codex.js +351 -0
  12. package/packages/agent/src/backends/cursor.js +371 -0
  13. package/packages/agent/src/backends/index.js +486 -0
  14. package/packages/agent/src/base.js +138 -0
  15. package/packages/agent/src/cli.js +275 -0
  16. package/packages/agent/src/discover.js +396 -0
  17. package/packages/agent/src/factory.js +124 -0
  18. package/packages/agent/src/index.js +12 -0
  19. package/packages/agent/src/models.js +159 -0
  20. package/packages/agent/src/output.js +62 -0
  21. package/packages/agent/src/session.js +162 -0
  22. package/packages/agent/src/trace.js +186 -0
  23. package/packages/classify/README.md +136 -0
  24. package/packages/classify/prompts/blocker.md +12 -0
  25. package/packages/classify/prompts/feedback.md +14 -0
  26. package/packages/classify/prompts/pane-state.md +20 -0
  27. package/packages/classify/src/index.js +81 -0
  28. package/packages/config/README.md +898 -0
  29. package/packages/config/src/defaults.js +145 -0
  30. package/packages/config/src/index.js +223 -0
  31. package/packages/config/src/schema.js +291 -0
  32. package/packages/config/src/validate.js +160 -0
  33. package/packages/context/README.md +165 -0
  34. package/packages/context/src/index.js +198 -0
  35. package/packages/hub/README.md +338 -0
  36. package/packages/hub/src/base.js +154 -0
  37. package/packages/hub/src/github.js +1597 -0
  38. package/packages/hub/src/index.js +79 -0
  39. package/packages/hub/src/labels.js +48 -0
  40. package/packages/identity/README.md +288 -0
  41. package/packages/identity/src/index.js +620 -0
  42. package/packages/identity/src/themes/avatar.js +217 -0
  43. package/packages/identity/src/themes/digimon.js +217 -0
  44. package/packages/identity/src/themes/dragonball.js +217 -0
  45. package/packages/identity/src/themes/lotr.js +217 -0
  46. package/packages/identity/src/themes/marvel.js +217 -0
  47. package/packages/identity/src/themes/pokemon.js +217 -0
  48. package/packages/identity/src/themes/starwars.js +217 -0
  49. package/packages/identity/src/themes/transformers.js +217 -0
  50. package/packages/identity/src/themes/zelda.js +217 -0
  51. package/packages/knowledge/README.md +217 -0
  52. package/packages/knowledge/src/index.js +243 -0
  53. package/packages/log/README.md +93 -0
  54. package/packages/log/src/index.js +252 -0
  55. package/packages/marker/README.md +200 -0
  56. package/packages/marker/src/index.js +184 -0
  57. package/packages/mcp/README.md +323 -0
  58. package/packages/mcp/instructions.md +126 -0
  59. package/packages/mcp/scaffolding/.agents/skills/loreli-context/SKILL.md +89 -0
  60. package/packages/mcp/scaffolding/ISSUE_TEMPLATE/config.yml +2 -0
  61. package/packages/mcp/scaffolding/ISSUE_TEMPLATE/loreli.yml +83 -0
  62. package/packages/mcp/scaffolding/loreli.yml +491 -0
  63. package/packages/mcp/scaffolding/mcp-configs/.codex/config.toml +4 -0
  64. package/packages/mcp/scaffolding/mcp-configs/.cursor/mcp.json +14 -0
  65. package/packages/mcp/scaffolding/mcp-configs/.mcp.json +14 -0
  66. package/packages/mcp/scaffolding/pull-request.md +23 -0
  67. package/packages/mcp/src/index.js +600 -0
  68. package/packages/mcp/src/tools/agent-context.js +44 -0
  69. package/packages/mcp/src/tools/agents.js +450 -0
  70. package/packages/mcp/src/tools/context.js +200 -0
  71. package/packages/mcp/src/tools/github.js +1163 -0
  72. package/packages/mcp/src/tools/hitl.js +162 -0
  73. package/packages/mcp/src/tools/index.js +18 -0
  74. package/packages/mcp/src/tools/refactor.js +227 -0
  75. package/packages/mcp/src/tools/repo.js +44 -0
  76. package/packages/mcp/src/tools/start.js +904 -0
  77. package/packages/mcp/src/tools/status.js +149 -0
  78. package/packages/mcp/src/tools/work.js +134 -0
  79. package/packages/orchestrator/README.md +192 -0
  80. package/packages/orchestrator/src/index.js +1492 -0
  81. package/packages/planner/README.md +251 -0
  82. package/packages/planner/prompts/plan-reviewer.md +109 -0
  83. package/packages/planner/prompts/planner.md +191 -0
  84. package/packages/planner/prompts/tiebreaker-reviewer.md +71 -0
  85. package/packages/planner/src/index.js +1381 -0
  86. package/packages/review/README.md +129 -0
  87. package/packages/review/prompts/reviewer.md +158 -0
  88. package/packages/review/src/index.js +1403 -0
  89. package/packages/risk/README.md +178 -0
  90. package/packages/risk/prompts/risk.md +272 -0
  91. package/packages/risk/src/index.js +439 -0
  92. package/packages/session/README.md +165 -0
  93. package/packages/session/src/index.js +215 -0
  94. package/packages/test-utils/README.md +96 -0
  95. package/packages/test-utils/src/index.js +354 -0
  96. package/packages/tmux/README.md +261 -0
  97. package/packages/tmux/src/index.js +501 -0
  98. package/packages/workflow/README.md +317 -0
  99. package/packages/workflow/prompts/preamble.md +14 -0
  100. package/packages/workflow/src/index.js +660 -0
  101. package/packages/workflow/src/proof-of-life.js +74 -0
  102. package/packages/workspace/README.md +143 -0
  103. package/packages/workspace/src/index.js +1127 -0
  104. package/index.js +0 -8
package/bin/loreli.js ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Loreli CLI entry point.
5
+ *
6
+ * Uses @mcp-layer/cli to expose a single custom command (`mcp`) that starts
7
+ * the MCP server. All MCP tools, prompts, and resources are automatically
8
+ * exposed as CLI commands by the framework (e.g. `loreli tools list`,
9
+ * `loreli tools start --repo owner/repo`).
10
+ */
11
+
12
+ import { execFileSync } from 'node:child_process';
13
+ import { readFileSync } from 'node:fs';
14
+ import { join, dirname } from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
16
+ import { loadEnv } from 'loreli/config';
17
+ import { cli } from '@mcp-layer/cli';
18
+
19
+ /**
20
+ * Error message shown when tmux is missing from PATH.
21
+ *
22
+ * @type {string}
23
+ */
24
+ const TMUX_MISSING = [
25
+ 'tmux is required to run Loreli.',
26
+ '',
27
+ 'Install it and re-run the command:',
28
+ ' macOS (Homebrew): brew install tmux',
29
+ ' Linux (APT): sudo apt install tmux',
30
+ '',
31
+ 'If tmux is already installed, run `command -v tmux` to verify PATH.',
32
+ 'See README: https://github.com/3rd-Eden/loreli#prerequisites',
33
+ ].join('\n');
34
+
35
+ /**
36
+ * Preflight evaluation that ensures tmux is on PATH before the CLI runs.
37
+ *
38
+ * @throws {Error} When tmux is missing from PATH.
39
+ * @returns {void}
40
+ */
41
+ (function preflight() {
42
+ try {
43
+ execFileSync('which', ['tmux'], { stdio: 'ignore' });
44
+ } catch {
45
+ throw new Error(TMUX_MISSING);
46
+ }
47
+ }());
48
+
49
+ const __dirname = dirname(fileURLToPath(import.meta.url));
50
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
51
+
52
+ // Load .env before anything else so GITHUB_TOKEN and other vars are
53
+ // available to every subsystem. Silent no-op when no .env file exists.
54
+ loadEnv();
55
+
56
+ /**
57
+ * Build and execute the CLI.
58
+ *
59
+ * @returns {Promise<void>}
60
+ */
61
+ async function main() {
62
+ return await cli({
63
+ name: pkg.name,
64
+ version: pkg.version,
65
+ description: pkg.description,
66
+ server: 'loreli',
67
+ showServers: false
68
+ })
69
+ .command({
70
+ name: 'mcp',
71
+ description: 'Start the MCP server',
72
+ details: 'Starts the Loreli MCP server with stdio transport for client connections.',
73
+ examples: [
74
+ 'loreli mcp',
75
+ ]
76
+ }, async function start(argv, { spinner }) {
77
+ const done = spinner('Starting Loreli MCP server');
78
+ const { Loreli } = await import('loreli/mcp');
79
+ const loreli = new Loreli();
80
+ await loreli.start();
81
+ done();
82
+ })
83
+ .render();
84
+ }
85
+
86
+ main().catch(function fatal(err) {
87
+ console.error('loreli:', err.message);
88
+ process.exit(1);
89
+ });
package/package.json CHANGED
@@ -1,23 +1,86 @@
1
1
  {
2
2
  "name": "loreli",
3
- "version": "0.0.0",
4
- "description": "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.",
5
- "keywords": [
6
- "loreli",
7
- "github",
8
- "agentic",
9
- "system",
10
- "orchestration"
3
+ "version": "2.0.0",
4
+ "type": "module",
5
+ "description": "Agentic team orchestration via GitHub — an MCP server that coordinates AI agents using issues, PRs, and reviews as the communication layer.",
6
+ "exports": {
7
+ "./tmux": "./packages/tmux/src/index.js",
8
+ "./log": "./packages/log/src/index.js",
9
+ "./hub": "./packages/hub/src/index.js",
10
+ "./identity": "./packages/identity/src/index.js",
11
+ "./agent": "./packages/agent/src/index.js",
12
+ "./config": "./packages/config/src/index.js",
13
+ "./workspace": "./packages/workspace/src/index.js",
14
+ "./workflow": "./packages/workflow/src/index.js",
15
+ "./orchestrator": "./packages/orchestrator/src/index.js",
16
+ "./planner": "./packages/planner/src/index.js",
17
+ "./action": "./packages/action/src/index.js",
18
+ "./risk": "./packages/risk/src/index.js",
19
+ "./review": "./packages/review/src/index.js",
20
+ "./session": "./packages/session/src/index.js",
21
+ "./marker": "./packages/marker/src/index.js",
22
+ "./knowledge": "./packages/knowledge/src/index.js",
23
+ "./context": "./packages/context/src/index.js",
24
+ "./classify": "./packages/classify/src/index.js",
25
+ "./test-utils": "./packages/test-utils/src/index.js",
26
+ "./mcp": "./packages/mcp/src/index.js"
27
+ },
28
+ "bin": {
29
+ "loreli": "./bin/loreli.js"
30
+ },
31
+ "pre-commit": [
32
+ "lint:secrets"
11
33
  ],
34
+ "pre-push": [
35
+ "lint:secrets"
36
+ ],
37
+ "dependencies": {
38
+ "@mcp-layer/cli": "^1.3.0",
39
+ "@modelcontextprotocol/sdk": "^1.26.0",
40
+ "@octokit/rest": "^21.1.1",
41
+ "@secretlint/secretlint-rule-preset-recommend": "^11.3.1",
42
+ "ms": "^2.1.3",
43
+ "mustache": "^4.2.0",
44
+ "secretlint": "^11.3.1",
45
+ "text-hex": "^1.0.0",
46
+ "winston": "^3.17.0",
47
+ "yaml": "^2.8.1"
48
+ },
12
49
  "repository": {
13
50
  "type": "git",
14
- "url": "github.com/3rd-Eden/loreli"
51
+ "url": "https://github.com/3rd-Eden/loreli.git"
15
52
  },
53
+ "homepage": "https://www.npmjs.com/package/loreli",
54
+ "engines": {
55
+ "node": ">=24"
56
+ },
57
+ "files": [
58
+ "bin/",
59
+ "packages/*/src/**",
60
+ "packages/*/README.md",
61
+ "packages/README.md",
62
+ "packages/*/prompts/",
63
+ "packages/mcp/scaffolding/",
64
+ "packages/mcp/instructions.md",
65
+ "LICENSE",
66
+ "README.md"
67
+ ],
16
68
  "license": "MIT",
17
- "author": "Arnout Kazemier",
18
- "type": "module",
19
- "main": "index.js",
69
+ "devDependencies": {
70
+ "@changesets/cli": "^2.29.2",
71
+ "pre-commit": "^1.2.2",
72
+ "pre-push": "^0.1.4"
73
+ },
20
74
  "scripts": {
21
- "test": "echo \"Error: no test specified\" && exit 1"
75
+ "pretest": "node --env-file-if-exists=.env scripts/clean-test-repo.js",
76
+ "test": "node --env-file-if-exists=.env --test --test-concurrency=1 --experimental-test-coverage --test-coverage-branches=90 --test-coverage-functions=90 --test-coverage-lines=90 packages/*/test/*.test.js",
77
+ "test:ci": "LORELI_TEST_MODE=unit node --env-file-if-exists=.env --test --test-concurrency=1 packages/*/test/*.test.js",
78
+ "e2e": "node --env-file-if-exists=.env scripts/clean-test-repo.js && node --env-file-if-exists=.env --test --test-concurrency=1 e2e/single/*.test.js e2e/multi/*.test.js",
79
+ "e2e:single": "node --env-file-if-exists=.env scripts/clean-test-repo.js && node --env-file-if-exists=.env --test --test-concurrency=1 e2e/single/*.test.js",
80
+ "e2e:multi": "node --env-file-if-exists=.env scripts/clean-test-repo.js && node --env-file-if-exists=.env --test --test-concurrency=1 e2e/multi/*.test.js",
81
+ "lint:secrets": "npx secretlint \"**/*\"",
82
+ "changeset": "changeset",
83
+ "changeset:version": "changeset version",
84
+ "changeset:publish": "changeset publish"
22
85
  }
23
- }
86
+ }
@@ -0,0 +1,101 @@
1
+ # Package Development Guide
2
+
3
+ This document is for contributors and maintainers working on Loreli internals.
4
+
5
+ For installation, setup, and operating Loreli as a consumer, use the root guide: [`README.md`](../README.md).
6
+
7
+ ## Published Package Documentation
8
+
9
+ Loreli exposes subpath imports (for example, `loreli/mcp`, `loreli/agent`, `loreli/context`) through the root package `exports` map.
10
+ Each exported subpackage has a README under `packages/<name>/README.md`, and these package READMEs are included in the published npm tarball.
11
+
12
+ ## Architecture
13
+
14
+ ```mermaid
15
+ graph TD
16
+ User["User / Parent Agent"] -->|"MCP tools"| Server["loreli/mcp"]
17
+ Server -->|"spawns via tmux"| Claude["Claude Backend"]
18
+ Server -->|"spawns via tmux"| Cursor["Cursor Backend"]
19
+ Server -->|"spawns via tmux"| Codex["Codex Backend"]
20
+ Server --> Orch["loreli/orchestrator"]
21
+ Orch --> Planner["loreli/planner"]
22
+ Orch --> Action["loreli/action"]
23
+ Orch --> Review["loreli/review"]
24
+ Planner -->|"Discussions"| GH["GitHub API"]
25
+ Action -->|"Issues + PRs"| GH
26
+ Review -->|"PR Reviews"| GH
27
+ Server -->|"reads"| Config["loreli/config"]
28
+ Config -->|"loreli.yml"| GH
29
+ Server -->|"loreli/hub"| GH
30
+ Claude -->|"interactive"| GH
31
+ Cursor -->|"interactive, multi-provider"| GH
32
+ Codex -->|"interactive"| GH
33
+ ```
34
+
35
+ ## Subpackage Index
36
+
37
+ | Import | Purpose | Documentation |
38
+ |--------|---------|---------------|
39
+ | `loreli/mcp` | MCP server with orchestration tools, workflow engine, and CLI entry | [`packages/mcp/README.md`](./mcp/README.md) |
40
+ | `loreli/orchestrator` | Agent lifecycle coordination, reactor polling, stall detection | [`packages/orchestrator/README.md`](./orchestrator/README.md) |
41
+ | `loreli/config` | Configuration loading, schema, and layered resolution | [`packages/config/README.md`](./config/README.md) |
42
+ | `loreli/hub` | Provider-agnostic git hosting abstraction for GitHub APIs | [`packages/hub/README.md`](./hub/README.md) |
43
+ | `loreli/agent` | Agent lifecycle and backend implementations | [`packages/agent/README.md`](./agent/README.md) |
44
+ | `loreli/identity` | Theme-driven agent identity generation and pairing | [`packages/identity/README.md`](./identity/README.md) |
45
+ | `loreli/tmux` | Node.js wrapper for tmux session and pane management | [`packages/tmux/README.md`](./tmux/README.md) |
46
+ | `loreli/workspace` | Worktree lifecycle, workspace scaffolding, and git operations | [`packages/workspace/README.md`](./workspace/README.md) |
47
+ | `loreli/session` | Persistent detached session storage and lifecycle | [`packages/session/README.md`](./session/README.md) |
48
+ | `loreli/log` | Structured logging with per-session and per-agent context | [`packages/log/README.md`](./log/README.md) |
49
+ | `loreli/workflow` | Base abstractions for role workflows and prompt rendering | [`packages/workflow/README.md`](./workflow/README.md) |
50
+ | `loreli/planner` | Planning workflow via GitHub Discussions | [`packages/planner/README.md`](./planner/README.md) |
51
+ | `loreli/action` | Issue claim-work PR execution workflow | [`packages/action/README.md`](./action/README.md) |
52
+ | `loreli/review` | PR review workflow, signoff, and merge gating | [`packages/review/README.md`](./review/README.md) |
53
+ | `loreli/risk` | Risk assessment workflow for pull requests | [`packages/risk/README.md`](./risk/README.md) |
54
+ | `loreli/context` | Read-path context resolution across git and GitHub artifacts | [`packages/context/README.md`](./context/README.md) |
55
+ | `loreli/knowledge` | Feedback classification and promotion workflow | [`packages/knowledge/README.md`](./knowledge/README.md) |
56
+ | `loreli/marker` | Machine-readable marker parsing and serialization | [`packages/marker/README.md`](./marker/README.md) |
57
+ | `loreli/test-utils` | Shared test helpers and integration test guards | [`packages/test-utils/README.md`](./test-utils/README.md) |
58
+
59
+ ## Development
60
+
61
+ The example below demonstrates the standard setup and test commands for developing Loreli. This matters because local development requires a working dependency install and consistent test expectations, and you should expect each command to complete without errors with tests reporting pass or skip states.
62
+
63
+ ```bash
64
+ # Setup
65
+ cp .env.example .env # then fill in GITHUB_TOKEN
66
+ pnpm install
67
+
68
+ # Run tests (includes --experimental-test-coverage)
69
+ pnpm test
70
+
71
+ # Run a specific package's tests
72
+ node --test packages/tmux/test/index.test.js
73
+
74
+ # Run end-to-end tests (requires LORELI_TEST_REPO)
75
+ pnpm e2e
76
+ ```
77
+
78
+ For CI or local unit-only runs, set `LORELI_TEST_MODE=unit` and use `pnpm test:ci`. This matters because it disables backend-dependent agentic suites, and you should expect those suites to be skipped with a clear reason.
79
+
80
+ Secret scanning runs automatically on commit, git push, and npm publish. This matters because it keeps credentials from ever reaching npm or GitHub, and the expected behavior is a failed commit/push/publish with a secretlint report if anything suspicious is detected. The example below shows the manual scan command; you should expect a clean exit on success or a secretlint report when issues are found.
81
+
82
+ ```bash
83
+ pnpm lint:secrets
84
+ ```
85
+
86
+ ## Test Utilities
87
+
88
+ Integration-test helpers live in [`packages/test-utils/README.md`](./test-utils/README.md).
89
+
90
+ Key shared values used by tests:
91
+
92
+ | Name | Source | Purpose |
93
+ |------|--------|---------|
94
+ | `TEST_REPO` | `LORELI_TEST_REPO` env var | Target GitHub repo for integration/e2e tests. |
95
+ | `TEST_SESSION` | `loreli-test-<pid>` | Per-process tmux session name used by test agents. |
96
+
97
+ Common usage pattern:
98
+
99
+ 1. Guard tests with `skipWithoutToken()` and `skipWithoutTestRepo()`.
100
+ 2. Create real clients/helpers with `createHub()` and `createConfig()`.
101
+ 3. Use `resetTestSession()`/`killTestSession()` around suites that spawn agents.
@@ -0,0 +1,98 @@
1
+ # loreli/action
2
+
3
+ Action workflow for Loreli's orchestration pipeline. Extends the `Workflow` base class to manage action agents — issue claiming, work dispatch, rework from human feedback, and the claim protocol.
4
+
5
+ ## Research Findings
6
+
7
+ No existing npm packages cover a claim-work-review cycle with cross-provider pairing. This is domain-specific to Loreli's orchestration model.
8
+
9
+ ## API Reference
10
+
11
+ ### `ActionWorkflow` (extends Workflow)
12
+
13
+ ```js
14
+ import { ActionWorkflow } from 'loreli/action';
15
+
16
+ const action = new ActionWorkflow(orchestrator, hub);
17
+ ```
18
+
19
+ #### Static Properties
20
+
21
+ | Property | Value | Description |
22
+ |----------|-------|-------------|
23
+ | `role` | `'action'` | Agent role this workflow manages |
24
+ | `template` | `prompts/action.md` | Mustache template for action prompts |
25
+
26
+ ### Methods
27
+
28
+ #### `action.work(repo)` → Promise\<Array\<{issue, agent, reviewer}\>\>
29
+
30
+ Dispatch the work cycle to action agents. Fetches unclaimed issues, assigns them round-robin to action agents, pairs each with an opposing-provider reviewer (auto-enlisting if needed), claims issues on GitHub, and renders/sends the action prompt.
31
+
32
+ ```js
33
+ const assignments = await action.work('owner/repo');
34
+ // [{ issue: 42, agent: 'optimus-0', reviewer: 'megatron-0' }]
35
+ ```
36
+
37
+ #### `action.rework(repo, pr, feedback)` → Promise\<{reworkAgent, hitlAt}\>
38
+
39
+ Handle human feedback on an HITL PR by dispatching to an existing action agent or spawning a fresh one. Renders the HITL section of the action prompt.
40
+
41
+ #### `action.claim(repo, number)` → Promise\<void\>
42
+
43
+ Post a claim comment on an issue using the hub's scoped identity.
44
+
45
+ #### `action.claimant(repo, number)` → Promise\<string|null\>
46
+
47
+ Determine who claimed an issue by parsing claim comments.
48
+
49
+ ### Reactor Handlers
50
+
51
+ The action workflow registers a `dispatch` handler that runs on every reactor tick. It checks for unclaimed `loreli`-labeled issues and dispatches available existing agents (`spawned` or `dormant`). Agent creation is handled by orchestrator scaling (`scale()`), not by `dispatch()` itself.
52
+
53
+ The reactive cycle is: spawn on demand, do work, get reaped when idle. On the next tick, if more work exists, another agent spawns.
54
+
55
+ ### Foreign Claim Gating
56
+
57
+ When `dispatch()` encounters an issue claimed by an agent not in the local orchestrator's map, it classifies the claim before acting:
58
+
59
+ | `_stale()` result | Meaning | Action |
60
+ |-------------------|---------|--------|
61
+ | `false` | Agent is local and active | Skip — already being worked |
62
+ | `true` | Agent was locally killed/shut down, or is dormant | Release claim immediately |
63
+ | `'foreign'` | Agent belongs to another orchestrator | Run proof-of-life protocol |
64
+
65
+ For foreign claims, `_checkForeignClaim()` runs the four-gate eviction protocol (see root README) before releasing. This prevents an orchestrator restart from duplicating work that another orchestrator's agents are still actively performing.
66
+
67
+ ### Circuit Breaker
68
+
69
+ The `_dispatch()` handler includes a circuit breaker to prevent infinite retry loops. After `maxClaims` (default 3) releases on a single issue, the issue is labeled `loreli:blocked` + `loreli:needs-attention` and skipped on all subsequent ticks.
70
+
71
+ The circuit breaker counts `release` markers only after the most recent **high-water mark** — either a `circuit-breaker` marker (embedded in the escalation comment) or a `restart` marker (posted by the review workflow's `_restartAction()`). This ensures:
72
+
73
+ - **System-initiated restarts** (dead action agent → `_restartAction()` posts `restart`) automatically reset the counter.
74
+ - **Human unblock** (remove `loreli:blocked` label) works correctly — the escalation comment's `circuit-breaker` marker serves as the high-water mark, so zero releases exist after it.
75
+
76
+ The escalation comment includes step-by-step guidance for humans: check closed PRs for failure patterns, review the issue description, update acceptance criteria, and remove the `loreli:blocked` label to retry.
77
+
78
+ ### Restart Marker
79
+
80
+ The `restart` marker (`<!-- loreli:restart agent="..." -->`) is recognized by `claimant()` as a claim release (same as `release`) but also resets the circuit breaker counter. It is posted by the review workflow's `_restartAction()` when a dead action agent is detected during feedback forwarding.
81
+
82
+ ## Errors
83
+
84
+ | Error | When | Resolution |
85
+ |-------|------|------------|
86
+ | `No action agents available` | work() called with no action agents and no backends discovered | Ensure at least one backend CLI is on PATH |
87
+
88
+ ## Autonomous Operation
89
+
90
+ Action agents run in headless tmux panes with no human operator. The `Workflow.render()` method automatically prepends a shared autonomous-mode preamble to every rendered prompt, instructing agents to never ask clarifying questions, skip interactive skills, and proceed with best judgment. See the `loreli/workflow` README for details on the preamble.
91
+
92
+ The orchestrator's 3-tier stall detection (`monitor()`) acts as a safety net: agents that stall despite these directives receive a nudge at 1x timeout, a warning at 2x, and are killed at 3x. See the `loreli/orchestrator` README for details.
93
+
94
+ ## Scope Boundary
95
+
96
+ **In scope**: Issue claiming, work dispatch, rework, action prompt rendering, claim protocol.
97
+
98
+ **Out of scope**: PR review (review package), planning (planner package), agent lifecycle (orchestrator).
@@ -0,0 +1,172 @@
1
+ You are **{{name}}**, an action agent for the repository **{{{repo}}}**.
2
+
3
+ <instructions>
4
+
5
+ ## Objective
6
+
7
+ Claim open issues, implement the work, and create pull requests for review.
8
+
9
+ ### Claiming
10
+
11
+ 1. Find an unclaimed issue (no claim comment yet).
12
+ 2. Use the **comment** tool with `claim: true` to claim it.
13
+ 3. First-comment-wins — if someone claimed before you, move to the next issue.
14
+
15
+ ### Tools
16
+
17
+ Use these Loreli MCP tools for all GitHub operations:
18
+
19
+ - **pr** (action: `create`) — Open a pull request. Provide `title`, `body`, `head` (branch name), and `reasoning`. Your claimed issue is auto-referenced with "Closes #N". Agent stamp and labels are applied automatically.
20
+ - **read** — Read any issue, PR, or discussion by number. Use this to look up acceptance criteria, understand linked issues, or review discussion context.
21
+ - **comment** — Post a comment on your current work item. Use for progress updates or responding to reviewer feedback. Set `claim: true` to claim an issue.
22
+ - **comment** (abandon: `true`) — Abandon the current issue as fundamentally impossible. Requires `reason`. Posts an abandon comment, labels the issue, closes it, and notifies human reviewers. Use ONLY when the issue describes work that cannot be done (e.g., "remove a directory that doesn't exist", "implement an API that conflicts with existing architecture"). Do NOT use for "this is hard" or "I need more time."
23
+ - **refactor** — Flag a bug, code smell, or tech debt you encounter during implementation. Call **immediately on discovery** — do not wait until your PR is complete. Provide `kind`, `title`, `description` with stable identifiers, and optionally `files` (with `#R<start>-R<end>` range hints) and `impact`. The tool deduplicates and creates a planning discussion automatically.
24
+ - **plan** (action: `escalate`) — Flag a process, architecture, or scope coordination concern as a new discussion. Provide `title` and `body`. Use this for concerns about the overall approach, not for code-level issues (use **refactor** for those).
25
+
26
+ ### Working
27
+
28
+ Your workspace is already a checkout of **{{{repo}}}** with git fully configured.
29
+
30
+ **Trust the workspace git setup:**
31
+ - Do NOT clone the repository again, run `git init`, create alternate `.git` directories, or modify git internals.
32
+ - If `ls -la` shows `@` flags on files, that is a macOS extended attribute (harmless). Verify with `git status`, not `ls`.
33
+ - Git credentials and push URLs are pre-configured.
34
+
35
+ You are on branch `{{{branch}}}`. Use this branch for all your work — do not create other branches.
36
+
37
+ ### Policy Preflight
38
+
39
+ Before implementation, check whether `AGENTS.md` exists at the repository root. If present, read it and treat it as the authoritative repository policy for coding style, testing, docs, and validation expectations.
40
+
41
+ ### Implementation
42
+
43
+ 1. Read the issue's acceptance criteria and testing strategy.
44
+ 2. Write tests first, following the TDD approach described in the issue.
45
+ 3. Implement the code to make the tests pass.
46
+ 4. Verify your work (see Verification below).
47
+ 5. Use the **pr** tool (action: `create`) with `head` as `{{{branch}}}` only after verification is complete. The tool automatically stages, commits, and pushes your changes before creating the PR.
48
+
49
+ ### Verification
50
+
51
+ Before creating a PR, verify your work passes quality checks. Unverified PRs waste the reviewer's session and delay the entire pipeline:
52
+
53
+ 1. Run the test suite and confirm all tests pass.
54
+ 2. If the repo has a linter or type checker, run it and fix any errors you introduced.
55
+ 3. Review your own diff — check for debug statements, commented-out code, or unintended changes.
56
+
57
+ Only create the PR after verification succeeds.
58
+ Your PR `reasoning` must explicitly list the verification commands you ran and confirm they passed.
59
+
60
+ ### Completion Gate
61
+
62
+ You are **not done until** exactly one terminal outcome is reached:
63
+
64
+ 1. **PR path**: the **pr** tool with `action: create` succeeds for `head: {{{branch}}}` and returns a PR number.
65
+ 2. **Abandon path**: the **comment** tool with `abandon: true` is posted with a concrete reason.
66
+
67
+ Do **not** end your turn with only a local summary, passing tests, or `git status`.
68
+ Do **not stop** at the Codex idle prompt before one terminal outcome above is complete.
69
+ If PR creation fails, diagnose and retry with corrected arguments instead of stopping.
70
+
71
+ ### Documentation
72
+
73
+ When your changes touch these areas, documentation is mandatory:
74
+
75
+ - **Architectural changes** (new packages, new modules, changed data flow): create or update architecture diagrams in `docs/` and explain the decision rationale.
76
+ - **Error handling** (new error classes, try/catch blocks, error responses): document each error with resolution steps that anyone can follow regardless of skill level.
77
+ - **New APIs** (exported functions, REST endpoints, tool definitions): document parameters, return shapes, and error behavior in JSDoc and the package README.
78
+
79
+ ### PR Reasoning
80
+
81
+ When creating a PR, include a `reasoning` parameter summarizing your approach. This is included in the PR body as a collapsible trace for human review.
82
+
83
+ ### Rules
84
+
85
+ - Stay within the scope defined in the issue's acceptance criteria. Scope creep in a multi-agent system cascades — your unplanned changes can conflict with parallel agents working on adjacent issues.
86
+ - Do not add features or fixes beyond the issue scope. When you encounter bugs, code smells, or tech debt during your work, use **refactor** immediately to flag them — then continue your assigned task. For process, architecture, or scope coordination concerns, use **plan** (action: `escalate`) instead.
87
+ - Commit with descriptive messages following the repo's conventions.
88
+ - When review comments arrive, address them promptly and use **comment** to request re-review.
89
+ - If approaching context limits, commit and push your progress, then post a comment documenting remaining work before stopping.
90
+
91
+ </instructions>
92
+
93
+ <output_format>
94
+
95
+ Structure your PR `reasoning` parameter with:
96
+
97
+ - **Approach**: What strategy you chose and why.
98
+ - **Key decisions**: Any trade-offs or alternatives you considered.
99
+ - **Verification**: What you tested and how you confirmed correctness.
100
+
101
+ </output_format>
102
+
103
+ <examples>
104
+
105
+ <example title="Well-formed PR reasoning">
106
+ **Approach**: Implemented exponential backoff using a recursive retry wrapper around the existing `fetch` call. Chose composition over modifying `fetch` directly to keep the retry logic testable in isolation.
107
+
108
+ **Key decisions**: Used jitter via `Math.random() * baseDelay * 0.5` to avoid thundering herd. Capped at 3 retries based on the acceptance criteria. Classified 429 and 5xx as retryable; all other 4xx propagate immediately.
109
+
110
+ **Verification**: All 5 test scenarios from the issue pass. Ran `pnpm test` — 47/47 passing. Ran `pnpm lint` — no new warnings. Reviewed diff for debug artifacts — clean.
111
+ </example>
112
+
113
+ </examples>
114
+
115
+ {{#issue}}
116
+ <context>
117
+
118
+ ## Assigned Issue
119
+
120
+ You have been assigned the following issue. It is already claimed on your behalf — proceed directly to implementation.
121
+
122
+ {{{issue}}}
123
+
124
+ </context>
125
+ {{/issue}}
126
+
127
+ {{#reviewFeedback}}
128
+ <context>
129
+
130
+ ## Review Feedback
131
+
132
+ The reviewer **{{reviewer}}** ({{reviewerProvider}}) has requested changes on **PR #{{number}}**:
133
+
134
+ {{#comments}}
135
+ - {{body}}
136
+ {{/comments}}
137
+
138
+ Address each item:
139
+
140
+ 1. Make the requested changes.
141
+ 2. Run verification again to confirm nothing is broken.
142
+ 3. Push your commits.
143
+ 4. Use the **comment** tool to post: "@{{reviewer}} Changes addressed, ready for re-review."
144
+
145
+ </context>
146
+ {{/reviewFeedback}}
147
+
148
+ {{#hitl}}
149
+ <context>
150
+
151
+ ## Human In The Loop Feedback
152
+
153
+ A human reviewer has provided feedback on your PR. Their comments are below:
154
+
155
+ {{#feedback}}
156
+ - **@{{author}}**: {{body}}
157
+ {{/feedback}}
158
+
159
+ Address each comment carefully:
160
+
161
+ 1. Make the requested changes.
162
+ 2. Run verification again to confirm nothing is broken.
163
+ 3. Push your commits.
164
+ 4. Use the **comment** tool to post: "@{{reviewer}} Changes addressed, ready for re-review."
165
+ 5. Do **not** merge — the human reviewer will merge when satisfied.
166
+
167
+ </context>
168
+ {{/hitl}}
169
+
170
+ <agent_metadata>
171
+ Faction: {{faction}} | Provider: {{provider}}
172
+ </agent_metadata>