loreli 0.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +710 -97
- package/bin/loreli.js +89 -0
- package/package.json +77 -14
- package/packages/README.md +101 -0
- package/packages/action/README.md +98 -0
- package/packages/action/prompts/action.md +172 -0
- package/packages/action/src/index.js +684 -0
- package/packages/agent/README.md +606 -0
- package/packages/agent/src/backends/claude.js +387 -0
- package/packages/agent/src/backends/codex.js +351 -0
- package/packages/agent/src/backends/cursor.js +371 -0
- package/packages/agent/src/backends/index.js +486 -0
- package/packages/agent/src/base.js +138 -0
- package/packages/agent/src/cli.js +275 -0
- package/packages/agent/src/discover.js +396 -0
- package/packages/agent/src/factory.js +124 -0
- package/packages/agent/src/index.js +12 -0
- package/packages/agent/src/models.js +159 -0
- package/packages/agent/src/output.js +62 -0
- package/packages/agent/src/session.js +162 -0
- package/packages/agent/src/trace.js +186 -0
- package/packages/classify/README.md +136 -0
- package/packages/classify/prompts/blocker.md +12 -0
- package/packages/classify/prompts/feedback.md +14 -0
- package/packages/classify/prompts/pane-state.md +20 -0
- package/packages/classify/src/index.js +81 -0
- package/packages/config/README.md +898 -0
- package/packages/config/src/defaults.js +145 -0
- package/packages/config/src/index.js +223 -0
- package/packages/config/src/schema.js +291 -0
- package/packages/config/src/validate.js +160 -0
- package/packages/context/README.md +165 -0
- package/packages/context/src/index.js +198 -0
- package/packages/hub/README.md +338 -0
- package/packages/hub/src/base.js +154 -0
- package/packages/hub/src/github.js +1597 -0
- package/packages/hub/src/index.js +79 -0
- package/packages/hub/src/labels.js +48 -0
- package/packages/identity/README.md +288 -0
- package/packages/identity/src/index.js +620 -0
- package/packages/identity/src/themes/avatar.js +217 -0
- package/packages/identity/src/themes/digimon.js +217 -0
- package/packages/identity/src/themes/dragonball.js +217 -0
- package/packages/identity/src/themes/lotr.js +217 -0
- package/packages/identity/src/themes/marvel.js +217 -0
- package/packages/identity/src/themes/pokemon.js +217 -0
- package/packages/identity/src/themes/starwars.js +217 -0
- package/packages/identity/src/themes/transformers.js +217 -0
- package/packages/identity/src/themes/zelda.js +217 -0
- package/packages/knowledge/README.md +217 -0
- package/packages/knowledge/src/index.js +243 -0
- package/packages/log/README.md +93 -0
- package/packages/log/src/index.js +252 -0
- package/packages/marker/README.md +200 -0
- package/packages/marker/src/index.js +184 -0
- package/packages/mcp/README.md +323 -0
- package/packages/mcp/instructions.md +126 -0
- package/packages/mcp/scaffolding/.agents/skills/loreli-context/SKILL.md +89 -0
- package/packages/mcp/scaffolding/ISSUE_TEMPLATE/config.yml +2 -0
- package/packages/mcp/scaffolding/ISSUE_TEMPLATE/loreli.yml +83 -0
- package/packages/mcp/scaffolding/loreli.yml +491 -0
- package/packages/mcp/scaffolding/mcp-configs/.codex/config.toml +4 -0
- package/packages/mcp/scaffolding/mcp-configs/.cursor/mcp.json +14 -0
- package/packages/mcp/scaffolding/mcp-configs/.mcp.json +14 -0
- package/packages/mcp/scaffolding/pull-request.md +23 -0
- package/packages/mcp/src/index.js +600 -0
- package/packages/mcp/src/tools/agent-context.js +44 -0
- package/packages/mcp/src/tools/agents.js +450 -0
- package/packages/mcp/src/tools/context.js +200 -0
- package/packages/mcp/src/tools/github.js +1163 -0
- package/packages/mcp/src/tools/hitl.js +162 -0
- package/packages/mcp/src/tools/index.js +18 -0
- package/packages/mcp/src/tools/refactor.js +227 -0
- package/packages/mcp/src/tools/repo.js +44 -0
- package/packages/mcp/src/tools/start.js +904 -0
- package/packages/mcp/src/tools/status.js +149 -0
- package/packages/mcp/src/tools/work.js +134 -0
- package/packages/orchestrator/README.md +192 -0
- package/packages/orchestrator/src/index.js +1492 -0
- package/packages/planner/README.md +251 -0
- package/packages/planner/prompts/plan-reviewer.md +109 -0
- package/packages/planner/prompts/planner.md +191 -0
- package/packages/planner/prompts/tiebreaker-reviewer.md +71 -0
- package/packages/planner/src/index.js +1381 -0
- package/packages/review/README.md +129 -0
- package/packages/review/prompts/reviewer.md +158 -0
- package/packages/review/src/index.js +1403 -0
- package/packages/risk/README.md +178 -0
- package/packages/risk/prompts/risk.md +272 -0
- package/packages/risk/src/index.js +439 -0
- package/packages/session/README.md +165 -0
- package/packages/session/src/index.js +215 -0
- package/packages/test-utils/README.md +96 -0
- package/packages/test-utils/src/index.js +354 -0
- package/packages/tmux/README.md +261 -0
- package/packages/tmux/src/index.js +501 -0
- package/packages/workflow/README.md +317 -0
- package/packages/workflow/prompts/preamble.md +14 -0
- package/packages/workflow/src/index.js +660 -0
- package/packages/workflow/src/proof-of-life.js +74 -0
- package/packages/workspace/README.md +143 -0
- package/packages/workspace/src/index.js +1127 -0
- package/index.js +0 -8
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { BaseHub } from './base.js';
|
|
2
|
+
import { GitHubHub } from './github.js';
|
|
3
|
+
export { definitions } from './labels.js';
|
|
4
|
+
|
|
5
|
+
export { BaseHub, GitHubHub };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Factory function that creates the appropriate hub implementation
|
|
9
|
+
* based on available tokens or explicit provider option.
|
|
10
|
+
*
|
|
11
|
+
* Token resolution order:
|
|
12
|
+
* 1. Explicit opts.token
|
|
13
|
+
* 2. loreli/config instance (opts.config) — reads through config's resolution chain
|
|
14
|
+
* 3. Environment variable (GITHUB_TOKEN) — direct fallback
|
|
15
|
+
*
|
|
16
|
+
* @param {object} [opts] - Configuration options.
|
|
17
|
+
* @param {string} [opts.provider] - Explicit provider ('github', future 'gitlab').
|
|
18
|
+
* @param {string} [opts.token] - Authentication token.
|
|
19
|
+
* @param {object} [opts.config] - loreli/config instance with a get() method.
|
|
20
|
+
* @returns {import('./base.js').BaseHub} A hub instance.
|
|
21
|
+
* @throws {Error} When no token is available for the selected provider.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```js
|
|
25
|
+
* // Auto-detect from environment
|
|
26
|
+
* const h = hub();
|
|
27
|
+
*
|
|
28
|
+
* // With loreli/config — token resolves via config's env layer
|
|
29
|
+
* const h = hub({ config });
|
|
30
|
+
*
|
|
31
|
+
* // Explicit token
|
|
32
|
+
* const h = hub({ provider: 'github', token: 'ghp_...' });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function hub(opts = {}) {
|
|
36
|
+
const provider = opts.provider ?? detect(opts.config);
|
|
37
|
+
const token = opts.token ?? tokenFrom(opts.config, provider);
|
|
38
|
+
|
|
39
|
+
if (!token) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`No token available for provider "${provider}". ` +
|
|
42
|
+
'Set GITHUB_TOKEN (or pass { token } explicitly).'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
switch (provider) {
|
|
47
|
+
case 'github':
|
|
48
|
+
return new GitHubHub({ token });
|
|
49
|
+
default:
|
|
50
|
+
throw new Error(`Unknown hub provider: "${provider}"`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Detect the provider from config or environment variables.
|
|
56
|
+
*
|
|
57
|
+
* @param {object} [config] - Optional loreli/config instance.
|
|
58
|
+
* @returns {string} The detected provider name.
|
|
59
|
+
*/
|
|
60
|
+
function detect(config) {
|
|
61
|
+
if (config?.get?.('github.token')) return 'github';
|
|
62
|
+
if (process.env.GITHUB_TOKEN) return 'github';
|
|
63
|
+
// Future: check GITLAB_TOKEN, GITEA_TOKEN, etc.
|
|
64
|
+
return 'github'; // default
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the token for a provider, checking config first then env.
|
|
69
|
+
*
|
|
70
|
+
* @param {object} [config] - Optional loreli/config instance.
|
|
71
|
+
* @param {string} provider - The provider name.
|
|
72
|
+
* @returns {string|undefined} The token, or undefined if not set.
|
|
73
|
+
*/
|
|
74
|
+
function tokenFrom(config, provider) {
|
|
75
|
+
switch (provider) {
|
|
76
|
+
case 'github': return config?.get?.('github.token') ?? process.env.GITHUB_TOKEN;
|
|
77
|
+
default: return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import hex from 'text-hex';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Known loreli: label descriptions keyed by suffix.
|
|
5
|
+
* Used to generate human-readable descriptions for namespaced labels.
|
|
6
|
+
*
|
|
7
|
+
* @type {Record<string, string>}
|
|
8
|
+
*/
|
|
9
|
+
const KNOWN = {
|
|
10
|
+
planner: 'Agent role: planner',
|
|
11
|
+
action: 'Agent role: action',
|
|
12
|
+
reviewer: 'Agent role: reviewer',
|
|
13
|
+
approved: 'Approved by reviewer agent',
|
|
14
|
+
'changes-requested': 'Changes requested by reviewer agent',
|
|
15
|
+
'needs-attention': 'Escalated — requires human attention',
|
|
16
|
+
parent: 'Parent tracking issue for a planning objective',
|
|
17
|
+
openai: 'AI provider: openai',
|
|
18
|
+
anthropic: 'AI provider: anthropic'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Build label definition objects (with deterministic colors) for hub.ensure().
|
|
23
|
+
*
|
|
24
|
+
* Colors are generated from the label name using text-hex — no hardcoded palette.
|
|
25
|
+
* Each unique label name always produces the same hex color.
|
|
26
|
+
*
|
|
27
|
+
* All agent labels use the `loreli:` namespace prefix to avoid collisions
|
|
28
|
+
* with existing repository labels. The base `loreli` label is the only
|
|
29
|
+
* one without the colon prefix.
|
|
30
|
+
*
|
|
31
|
+
* @param {string[]} names - Label names (e.g. ['loreli', 'loreli:planner']).
|
|
32
|
+
* @returns {Array<{name: string, color: string, description: string}>}
|
|
33
|
+
*/
|
|
34
|
+
export function definitions(names) {
|
|
35
|
+
return names.map(function define(name) {
|
|
36
|
+
const color = hex(name).replace('#', '');
|
|
37
|
+
let description = '';
|
|
38
|
+
|
|
39
|
+
if (name === 'loreli') {
|
|
40
|
+
description = 'Managed by Loreli agent orchestration';
|
|
41
|
+
} else if (name.startsWith('loreli:')) {
|
|
42
|
+
const suffix = name.slice('loreli:'.length);
|
|
43
|
+
description = KNOWN[suffix] ?? `Loreli: ${suffix}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return { name, color, description };
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# loreli/identity
|
|
2
|
+
|
|
3
|
+
Themed agent naming with provider-based yin/yang pairing. Also provides model-identity utility functions (`display`, `infer`) that convert raw model strings to human-readable forms and infer provider from model names.
|
|
4
|
+
|
|
5
|
+
When OpenAI agents create work, Anthropic agents review it (and vice versa), creating adversarial quality checks through themed identity assignment. Multi-provider backends like Cursor Agent are assigned to the faction matching their configured model's provider.
|
|
6
|
+
|
|
7
|
+
## API Reference
|
|
8
|
+
|
|
9
|
+
### `display(model)` → string
|
|
10
|
+
|
|
11
|
+
Convert a full API model identifier to a human-readable display name by stripping trailing date suffixes (e.g. `-20250514`). Returns the input unchanged when no date suffix is found.
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { display } from 'loreli/identity';
|
|
15
|
+
|
|
16
|
+
display('claude-sonnet-4-20250514'); // 'claude-sonnet-4'
|
|
17
|
+
display('gpt-4o'); // 'gpt-4o'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### `infer(model)` → string
|
|
21
|
+
|
|
22
|
+
Infer the AI provider from a model identifier string using prefix-based heuristics. Returns `'anthropic'` for claude models, `'openai'` for gpt/o-series models, and `'unknown'` for unrecognized models.
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
import { infer } from 'loreli/identity';
|
|
26
|
+
|
|
27
|
+
infer('claude-sonnet-4-20250514'); // 'anthropic'
|
|
28
|
+
infer('gpt-4o'); // 'openai'
|
|
29
|
+
infer('o3-mini'); // 'openai'
|
|
30
|
+
infer('gemini-pro'); // 'unknown'
|
|
31
|
+
infer(null); // 'unknown'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### `side(provider)` → `'yang' | 'yin'`
|
|
35
|
+
|
|
36
|
+
Resolve the yin/yang side for a provider. Known providers use explicit mappings; unknown providers are assigned deterministically using a stable hash so pairing remains consistent across runs.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
import { side } from 'loreli/identity';
|
|
40
|
+
|
|
41
|
+
side('openai'); // 'yang'
|
|
42
|
+
side('anthropic'); // 'yin'
|
|
43
|
+
side('cursor-openai'); // 'yang'
|
|
44
|
+
side('cursor-anthropic'); // 'yin'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### `vendor(provider)` → string
|
|
48
|
+
|
|
49
|
+
Normalize provider names to canonical vendor names for model/config lookups. Cursor virtual providers strip the `cursor-` prefix.
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import { vendor } from 'loreli/identity';
|
|
53
|
+
|
|
54
|
+
vendor('cursor-openai'); // 'openai'
|
|
55
|
+
vendor('cursor-anthropic'); // 'anthropic'
|
|
56
|
+
vendor('openai'); // 'openai'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `pick(themes)` → string
|
|
60
|
+
|
|
61
|
+
Select a single theme from a config value that may be a string or an array of theme names. When given an array, picks one element at random. When given a string, returns it directly. Falls back to `'transformers'` for nullish input.
|
|
62
|
+
|
|
63
|
+
This is the randomization entry point for multi-theme configs. Callers invoke `pick()` once at the work-item boundary (first agent added), then thread the resolved theme to all subsequent agents in the same work item so antagonist pairs always share the same theme universe.
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
import { pick } from 'loreli/identity';
|
|
67
|
+
|
|
68
|
+
pick('pokemon'); // 'pokemon'
|
|
69
|
+
pick(['pokemon', 'marvel', 'zelda']); // random: 'pokemon', 'marvel', or 'zelda'
|
|
70
|
+
pick(null); // 'transformers'
|
|
71
|
+
pick(undefined); // 'transformers'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### `council(theme)` → string
|
|
75
|
+
|
|
76
|
+
Get the council authority name for a given theme. Returns `'Council'` as fallback for unknown themes.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
import { council } from 'loreli/identity';
|
|
80
|
+
|
|
81
|
+
council('transformers'); // 'The Allspark'
|
|
82
|
+
council('pokemon'); // 'Professor Oak'
|
|
83
|
+
council('marvel'); // 'S.H.I.E.L.D.'
|
|
84
|
+
council('unknown'); // 'Council'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### `Identity`
|
|
88
|
+
|
|
89
|
+
Represents a unique, themed agent identity.
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
import { Identity } from 'loreli/identity';
|
|
93
|
+
|
|
94
|
+
const id = new Identity({
|
|
95
|
+
name: 'optimus', instance: 0, faction: 'autobots',
|
|
96
|
+
provider: 'openai', model: 'gpt-4o', theme: 'transformers'
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
id.name; // 'optimus-0'
|
|
100
|
+
id.character; // 'optimus'
|
|
101
|
+
id.faction; // 'autobots'
|
|
102
|
+
id.provider; // 'openai'
|
|
103
|
+
id.toJSON(); // serializable plain object
|
|
104
|
+
id.labels(); // ['loreli', 'provider:openai', 'model:gpt-4o']
|
|
105
|
+
id.labels('action'); // ['loreli', 'provider:openai', 'model:gpt-4o', 'role:action']
|
|
106
|
+
id.signoff(); // 'Autobots, roll out!'
|
|
107
|
+
id.signature('action'); // full markdown signature block (see below)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Council Identity
|
|
111
|
+
|
|
112
|
+
For orchestrator-level interactions, create a council identity by omitting `instance` and setting `council: true`. Council identities use the theme's central authority for signoffs and produce names without instance suffixes.
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
import { Identity, council } from 'loreli/identity';
|
|
116
|
+
|
|
117
|
+
const id = new Identity({
|
|
118
|
+
name: 'Loreli',
|
|
119
|
+
provider: 'loreli',
|
|
120
|
+
model: 'mcp',
|
|
121
|
+
theme: 'transformers',
|
|
122
|
+
faction: council('transformers'), // 'The Allspark'
|
|
123
|
+
council: true
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
id.name; // 'Loreli' (no instance suffix)
|
|
127
|
+
id.faction; // 'The Allspark'
|
|
128
|
+
id.signoff(); // 'Till all are one.' (council signoff, not faction)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
#### `identity.labels(role?)` → string[]
|
|
132
|
+
|
|
133
|
+
Generate GitHub label names that identify this agent. Model names are converted to human-readable display names (e.g. `claude-sonnet-4` instead of `claude-sonnet-4-20250514`). Pass an optional `role` to include a `role:` label.
|
|
134
|
+
|
|
135
|
+
This is the single source of truth for what labels an agent should apply to GitHub issues and PRs.
|
|
136
|
+
|
|
137
|
+
#### `identity.signoff()` → string
|
|
138
|
+
|
|
139
|
+
Returns a randomly selected, faction-specific sign-off message from the agent's theme. Each faction has 30 unique messages. The selection is random per call, giving each GitHub interaction a unique personality.
|
|
140
|
+
|
|
141
|
+
#### `identity.signature(role)` → string
|
|
142
|
+
|
|
143
|
+
Generates a full markdown signature block for GitHub comments. Every agent communication (claims, approvals, relay output) is stamped with this block, making each interaction traceable to a specific agent, model, and loreli version.
|
|
144
|
+
|
|
145
|
+
The signature block includes a themed sign-off message above a metadata table:
|
|
146
|
+
|
|
147
|
+
```markdown
|
|
148
|
+
***
|
|
149
|
+
|
|
150
|
+
Autobots, roll out! — **optimus-0**
|
|
151
|
+
|
|
152
|
+
| Agent | Model | Provider | Faction | Role | Version |
|
|
153
|
+
|-------|-------|----------|---------|------|---------|
|
|
154
|
+
| optimus-0 | gpt-4o | openai | autobots | action | `loreli@0.0.0` |
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
This is automatically appended by claim, signoff, and relay comments in the orchestration workflow.
|
|
158
|
+
|
|
159
|
+
### `Registry`
|
|
160
|
+
|
|
161
|
+
Manages identity assignment, tracking, and yin/yang pairing.
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
import { Registry } from 'loreli/identity';
|
|
165
|
+
|
|
166
|
+
const registry = new Registry();
|
|
167
|
+
|
|
168
|
+
// Acquire an identity
|
|
169
|
+
const agent = registry.acquire('transformers', 'openai', 'gpt-4o');
|
|
170
|
+
// -> Identity { name: 'optimus-0', faction: 'autobots' }
|
|
171
|
+
|
|
172
|
+
// Find the polar opposite for review
|
|
173
|
+
const opp = registry.opposite(agent);
|
|
174
|
+
// -> { provider: 'anthropic', faction: 'decepticons' }
|
|
175
|
+
|
|
176
|
+
// List all active identities
|
|
177
|
+
registry.active(); // [Identity, ...]
|
|
178
|
+
|
|
179
|
+
// Release when agent is done
|
|
180
|
+
registry.release(agent);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### `registry.acquire(theme, provider, model?)` → Identity
|
|
184
|
+
|
|
185
|
+
Assigns the next available character name from the theme's faction. Characters are round-robin; when all 10 are used, instance counters increment (e.g. `optimus-0`, then `optimus-1`).
|
|
186
|
+
|
|
187
|
+
#### `registry.release(identity)`
|
|
188
|
+
|
|
189
|
+
Returns an identity to the pool.
|
|
190
|
+
|
|
191
|
+
#### `registry.active()` → Identity[]
|
|
192
|
+
|
|
193
|
+
Returns all currently active identities.
|
|
194
|
+
|
|
195
|
+
#### `registry.opposite(identity)` → { provider, faction }
|
|
196
|
+
|
|
197
|
+
Returns the opposing provider and faction for yin/yang review pairing.
|
|
198
|
+
|
|
199
|
+
#### `registry.pair(identity, candidates)` → object | null
|
|
200
|
+
|
|
201
|
+
Find the opposing-provider match from a list of candidates. Each candidate must have an `identity` property with a `provider` field. Returns the first candidate whose provider opposes the given identity, or `null`.
|
|
202
|
+
|
|
203
|
+
This is the authoritative place for cross-provider matching logic. The orchestrator delegates to this method instead of implementing its own search.
|
|
204
|
+
|
|
205
|
+
```js
|
|
206
|
+
const action = registry.acquire('transformers', 'openai');
|
|
207
|
+
const reviewers = [
|
|
208
|
+
{ identity: registry.acquire('transformers', 'anthropic'), role: 'reviewer' },
|
|
209
|
+
{ identity: registry.acquire('transformers', 'openai'), role: 'reviewer' }
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
const match = registry.pair(action, reviewers);
|
|
213
|
+
// → the anthropic reviewer (opposing provider)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### `identity.proofOfLife(agent)` → string
|
|
217
|
+
|
|
218
|
+
Returns a randomly selected proof-of-life request message from the theme's **council** — the central authority that transcends the yang/yin faction split. The `{agent}` placeholder in the theme message is replaced with the provided agent name.
|
|
219
|
+
|
|
220
|
+
Proof-of-life is an orchestrator-level concern (the system checking on its agents), so messages come from the council rather than a faction. Each theme has a named council authority and at least 10 unique messages.
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
const id = new Identity({
|
|
224
|
+
name: 'optimus', instance: 0, faction: 'autobots',
|
|
225
|
+
provider: 'openai', model: 'gpt-4o', theme: 'transformers'
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
id.proofOfLife('megatron-0');
|
|
229
|
+
// 'The Allspark calls upon **megatron-0** — report your status.'
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Falls back to a plain `Requesting proof of life from **{agent}**` when theme data is missing.
|
|
233
|
+
|
|
234
|
+
## Council
|
|
235
|
+
|
|
236
|
+
Each theme includes a `council` section representing the central authority that oversees both factions. The council is used for orchestrator-level interactions like proof-of-life checks, where messages should not be faction-specific. Each council provides:
|
|
237
|
+
|
|
238
|
+
- `name` — The authority's display name
|
|
239
|
+
- `proofOfLife` — 10 themed messages for liveness checks (use `{agent}` placeholder)
|
|
240
|
+
- `signoffs` — 5 sign-off messages for council-level GitHub comments
|
|
241
|
+
|
|
242
|
+
| Theme | Council Authority |
|
|
243
|
+
|-------|-------------------|
|
|
244
|
+
| Transformers | The Allspark |
|
|
245
|
+
| Pokemon | Professor Oak |
|
|
246
|
+
| Marvel | S.H.I.E.L.D. |
|
|
247
|
+
| Digimon | Yggdrasil |
|
|
248
|
+
| Star Wars | The Force |
|
|
249
|
+
| LOTR | The Valar |
|
|
250
|
+
| Dragon Ball | Grand Zeno |
|
|
251
|
+
| Avatar | Raava |
|
|
252
|
+
| Zelda | Hylia |
|
|
253
|
+
|
|
254
|
+
## Themes
|
|
255
|
+
|
|
256
|
+
| Theme | OpenAI (Yang) | Anthropic (Yin) |
|
|
257
|
+
|-------|---------------|-----------------|
|
|
258
|
+
| `transformers` | Autobots (Optimus, Bumblebee, Jazz, ...) | Decepticons (Megatron, Starscream, ...) |
|
|
259
|
+
| `pokemon` | Fire (Charizard, Arcanine, ...) | Water (Blastoise, Gyarados, ...) |
|
|
260
|
+
| `marvel` | Avengers (IronMan, Captain, Thor, ...) | X-Men (Wolverine, Cyclops, ...) |
|
|
261
|
+
| `digimon` | Vaccine (Agumon, Gabumon, ...) | Virus (Devimon, Myotismon, ...) |
|
|
262
|
+
| `starwars` | Jedi (Luke, Obiwan, Yoda, ...) | Sith (Vader, Palpatine, Maul, ...) |
|
|
263
|
+
| `lotr` | Fellowship (Gandalf, Aragorn, Legolas, ...) | Mordor (Sauron, Saruman, Witchking, ...) |
|
|
264
|
+
| `dragonball` | Z Fighters (Goku, Vegeta, Gohan, ...) | Villains (Frieza, Cell, Buu, ...) |
|
|
265
|
+
| `avatar` | Benders (Aang, Katara, Toph, ...) | Fire Nation (Ozai, Azula, Amon, ...) |
|
|
266
|
+
| `zelda` | Hyrule (Link, Zelda, Impa, ...) | Shadow (Ganondorf, Majora, Zant, ...) |
|
|
267
|
+
|
|
268
|
+
Each faction contains 10 characters and 30 sign-off messages.
|
|
269
|
+
|
|
270
|
+
## Sign-Off Messages
|
|
271
|
+
|
|
272
|
+
Every faction has its own set of themed sign-off messages that are randomly selected for each GitHub comment. Examples:
|
|
273
|
+
|
|
274
|
+
| Theme | Yang (OpenAI) | Yin (Anthropic) |
|
|
275
|
+
|-------|---------------|-----------------|
|
|
276
|
+
| Transformers | "Autobots, roll out!" | "Peace through tyranny." |
|
|
277
|
+
| Pokemon | "The flame burns bright!" | "Surf's up!" |
|
|
278
|
+
| Marvel | "Avengers, assemble!" | "To me, my X-Men!" |
|
|
279
|
+
| Digimon | "Digivolve into champion!" | "Darkness is the ultimate debugger." |
|
|
280
|
+
| Star Wars | "May the Force be with you." | "I find your lack of tests disturbing." |
|
|
281
|
+
| LOTR | "You shall not pass — without tests!" | "One codebase to rule them all." |
|
|
282
|
+
| Dragon Ball | "It's over 9000 commits!" | "This isn't even my final form." |
|
|
283
|
+
| Avatar | "The code is like water — it flows where it needs to." | "Everything changed when the fire nation committed." |
|
|
284
|
+
| Zelda | "It's dangerous to go alone — take this PR." | "You've met with a terrible fate, haven't you?" |
|
|
285
|
+
|
|
286
|
+
## Naming Convention
|
|
287
|
+
|
|
288
|
+
Names follow `{character}-{instance}` where instance increments per reuse: `optimus-0`, `optimus-1`. This ensures uniqueness across sessions.
|