@gamaze/hicortex 0.19.1 → 0.19.2
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 +4 -1
- package/assets/identity.html +59 -8
- package/dist/identity-store.d.ts +65 -1
- package/dist/identity-store.js +132 -9
- package/dist/index.d.ts +22 -7
- package/dist/index.js +510 -86
- package/dist/learnings-identity.d.ts +19 -10
- package/dist/learnings-identity.js +30 -19
- package/dist/mcp-server.js +9 -13
- package/dist/prompts.js +21 -1
- package/dist/types.d.ts +14 -0
- package/hermes-plugin/hicortex/provider.py +21 -5
- package/openclaw.plugin.json +15 -7
- package/package.json +1 -1
|
@@ -63,18 +63,25 @@ export declare function resolveConfig(): ResolvedConfig | null;
|
|
|
63
63
|
*/
|
|
64
64
|
export declare function titleCaseSection(name: string): string;
|
|
65
65
|
/**
|
|
66
|
-
* Stable section ordering
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
66
|
+
* Stable section ordering for the rendered `## Identity` block: the #313
|
|
67
|
+
* precedence contract — `agent_identity` (the agent's own self + role
|
|
68
|
+
* conduct) first, then `user` (the principal), then `rules` (fleet-wide house
|
|
69
|
+
* rules), then every other section alphabetically. The list is imported from
|
|
70
|
+
* identity-store (SECTION_PRECEDENCE) so the server's SERVED order and every
|
|
71
|
+
* client's RENDERED order are the same definition — they cannot drift.
|
|
72
|
+
* Server-side enumeration order (readdirSync) is FS-dependent, so we sort
|
|
73
|
+
* here for a deterministic injection block. Exported for reuse by the OC
|
|
74
|
+
* plugin; the Python Hermes plugin mirrors this helper — keep them in sync.
|
|
70
75
|
*/
|
|
71
76
|
export declare function orderSectionNames(names: string[]): string[];
|
|
72
77
|
/**
|
|
73
78
|
* Render the `## Identity` block from a resolved section map, or null when there
|
|
74
79
|
* is nothing to inject (no sections, or every section blank after trimming).
|
|
75
80
|
* Pure — no gating, no I/O. Shared verbatim by the CC hook and the OC plugin so
|
|
76
|
-
* both harnesses emit an identical block. Sections are ordered (
|
|
77
|
-
* then alphabetical) and rendered under
|
|
81
|
+
* both harnesses emit an identical block. Sections are ordered (agent_identity,
|
|
82
|
+
* user, rules, then alphabetical) and rendered under `###` headings labeled by
|
|
83
|
+
* the #313 scope map (SECTION_LABELS: "Agent identity" / "User" / "Global
|
|
84
|
+
* rules"); unknown section names fall back to title-case.
|
|
78
85
|
*/
|
|
79
86
|
export declare function renderIdentityBlock(sections: Record<string, string>): string | null;
|
|
80
87
|
/**
|
|
@@ -116,10 +123,12 @@ export interface IdentityToolResult {
|
|
|
116
123
|
* `agent` param forwarded so per-agent installs resolve the right scope
|
|
117
124
|
* (WARNING-2: previously the tool always passed `{}` → global, so an agent
|
|
118
125
|
* with an override saw the wrong identity).
|
|
119
|
-
* 2. `
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
126
|
+
* 2. `serveIdentityBody` — the ONE composition helper (REST uses it too):
|
|
127
|
+
* injects the synthetic product-owned `memory` section (WARNING-1: the
|
|
128
|
+
* REST route + SessionStart hook inject it; the tool did not,
|
|
129
|
+
* contradicting its "same data" docs) and applies the SECTION_PRECEDENCE
|
|
130
|
+
* wire order.
|
|
131
|
+
* 3. optional `name` filter, then `renderIdentityBlock` for the `### <Label>`
|
|
123
132
|
* markdown the hook injects.
|
|
124
133
|
*
|
|
125
134
|
* Pure: no I/O of its own (the only I/O is `handleIdentityGet` reading the
|
|
@@ -39,7 +39,6 @@ exports.fetchLessonsIdentity = fetchLessonsIdentity;
|
|
|
39
39
|
const node_fs_1 = require("node:fs");
|
|
40
40
|
const node_path_1 = require("node:path");
|
|
41
41
|
const identity_store_js_1 = require("./identity-store.js");
|
|
42
|
-
const memory_instructions_js_1 = require("./memory-instructions.js");
|
|
43
42
|
const features_js_1 = require("./features.js");
|
|
44
43
|
const extensions_js_1 = require("./extensions.js");
|
|
45
44
|
const state_js_1 = require("./state.js");
|
|
@@ -152,22 +151,29 @@ function titleCaseSection(name) {
|
|
|
152
151
|
.join(" ");
|
|
153
152
|
}
|
|
154
153
|
/**
|
|
155
|
-
* Stable section ordering
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
154
|
+
* Stable section ordering for the rendered `## Identity` block: the #313
|
|
155
|
+
* precedence contract — `agent_identity` (the agent's own self + role
|
|
156
|
+
* conduct) first, then `user` (the principal), then `rules` (fleet-wide house
|
|
157
|
+
* rules), then every other section alphabetically. The list is imported from
|
|
158
|
+
* identity-store (SECTION_PRECEDENCE) so the server's SERVED order and every
|
|
159
|
+
* client's RENDERED order are the same definition — they cannot drift.
|
|
160
|
+
* Server-side enumeration order (readdirSync) is FS-dependent, so we sort
|
|
161
|
+
* here for a deterministic injection block. Exported for reuse by the OC
|
|
162
|
+
* plugin; the Python Hermes plugin mirrors this helper — keep them in sync.
|
|
159
163
|
*/
|
|
160
164
|
function orderSectionNames(names) {
|
|
161
|
-
const primaries =
|
|
162
|
-
const rest = names.filter((n) => n
|
|
165
|
+
const primaries = identity_store_js_1.SECTION_PRECEDENCE.filter((p) => names.includes(p));
|
|
166
|
+
const rest = names.filter((n) => !identity_store_js_1.SECTION_PRECEDENCE.includes(n)).sort();
|
|
163
167
|
return [...primaries, ...rest];
|
|
164
168
|
}
|
|
165
169
|
/**
|
|
166
170
|
* Render the `## Identity` block from a resolved section map, or null when there
|
|
167
171
|
* is nothing to inject (no sections, or every section blank after trimming).
|
|
168
172
|
* Pure — no gating, no I/O. Shared verbatim by the CC hook and the OC plugin so
|
|
169
|
-
* both harnesses emit an identical block. Sections are ordered (
|
|
170
|
-
* then alphabetical) and rendered under
|
|
173
|
+
* both harnesses emit an identical block. Sections are ordered (agent_identity,
|
|
174
|
+
* user, rules, then alphabetical) and rendered under `###` headings labeled by
|
|
175
|
+
* the #313 scope map (SECTION_LABELS: "Agent identity" / "User" / "Global
|
|
176
|
+
* rules"); unknown section names fall back to title-case.
|
|
171
177
|
*/
|
|
172
178
|
function renderIdentityBlock(sections) {
|
|
173
179
|
if (!sections || typeof sections !== "object" || Array.isArray(sections))
|
|
@@ -178,7 +184,11 @@ function renderIdentityBlock(sections) {
|
|
|
178
184
|
const body = sections[name];
|
|
179
185
|
if (typeof body !== "string" || body.trim() === "")
|
|
180
186
|
continue;
|
|
181
|
-
|
|
187
|
+
// Own-property lookup (CR-A): "constructor" is allowlist-VALID, and a
|
|
188
|
+
// plain SECTION_LABELS[name] would resolve through the Object.prototype
|
|
189
|
+
// chain and render the inherited function's source as the heading.
|
|
190
|
+
const label = Object.hasOwn(identity_store_js_1.SECTION_LABELS, name) ? identity_store_js_1.SECTION_LABELS[name] : titleCaseSection(name);
|
|
191
|
+
bodyParts.push(`### ${label}`, "", body.trim());
|
|
182
192
|
}
|
|
183
193
|
if (bodyParts.length === 0)
|
|
184
194
|
return null;
|
|
@@ -195,10 +205,12 @@ function renderIdentityBlock(sections) {
|
|
|
195
205
|
* `agent` param forwarded so per-agent installs resolve the right scope
|
|
196
206
|
* (WARNING-2: previously the tool always passed `{}` → global, so an agent
|
|
197
207
|
* with an override saw the wrong identity).
|
|
198
|
-
* 2. `
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
208
|
+
* 2. `serveIdentityBody` — the ONE composition helper (REST uses it too):
|
|
209
|
+
* injects the synthetic product-owned `memory` section (WARNING-1: the
|
|
210
|
+
* REST route + SessionStart hook inject it; the tool did not,
|
|
211
|
+
* contradicting its "same data" docs) and applies the SECTION_PRECEDENCE
|
|
212
|
+
* wire order.
|
|
213
|
+
* 3. optional `name` filter, then `renderIdentityBlock` for the `### <Label>`
|
|
202
214
|
* markdown the hook injects.
|
|
203
215
|
*
|
|
204
216
|
* Pure: no I/O of its own (the only I/O is `handleIdentityGet` reading the
|
|
@@ -209,7 +221,10 @@ function buildIdentityToolResult(identityDir, identityClients, identityAgents, o
|
|
|
209
221
|
// WARNING-2: forward `agent` so per-agent installs resolve the right scope.
|
|
210
222
|
// An invalid id makes handleIdentityGet return a 400 → surfaced as isError.
|
|
211
223
|
const query = opts.agent ? { agent: opts.agent } : {};
|
|
212
|
-
|
|
224
|
+
// WARNING-1: inject the synthetic `memory` section exactly like REST + the
|
|
225
|
+
// SessionStart hook — via the ONE composition helper (serveIdentityBody,
|
|
226
|
+
// #313 CR3) so the tool's served order is the routes' served order.
|
|
227
|
+
const r = (0, identity_store_js_1.serveIdentityBody)((0, identity_store_js_1.handleIdentityGet)(identityDir, identityClients, query, identityAgents), opts.memoryInstructionsEnabled);
|
|
213
228
|
if (r.status !== 200) {
|
|
214
229
|
const errBody = r.body;
|
|
215
230
|
return {
|
|
@@ -217,10 +232,6 @@ function buildIdentityToolResult(identityDir, identityClients, identityAgents, o
|
|
|
217
232
|
isError: true,
|
|
218
233
|
};
|
|
219
234
|
}
|
|
220
|
-
// WARNING-1: inject the synthetic `memory` section exactly like REST + the
|
|
221
|
-
// SessionStart hook. `injectMemorySection` is a no-op when disabled or when
|
|
222
|
-
// agent mode === "off".
|
|
223
|
-
(0, memory_instructions_js_1.injectMemorySection)(r.body, opts.memoryInstructionsEnabled);
|
|
224
235
|
const sections = r.body.sections ?? {};
|
|
225
236
|
const filtered = opts.name
|
|
226
237
|
? (sections[opts.name] !== undefined ? { [opts.name]: sections[opts.name] } : {})
|
package/dist/mcp-server.js
CHANGED
|
@@ -309,7 +309,7 @@ function createMcpServer() {
|
|
|
309
309
|
const identityDir = (0, node_path_1.join)(stateDir, "identity");
|
|
310
310
|
// Single pipeline shared with REST /identity + the SessionStart hook
|
|
311
311
|
// (#264 CRITICAL + WARNING-1 + WARNING-2). The pure function owns
|
|
312
|
-
// handleIdentityGet →
|
|
312
|
+
// handleIdentityGet → serveIdentityBody → renderIdentityBlock.
|
|
313
313
|
const result = (0, learnings_identity_js_1.buildIdentityToolResult)(identityDir, identityClients, identityAgents, {
|
|
314
314
|
name,
|
|
315
315
|
agent,
|
|
@@ -975,14 +975,11 @@ async function startServer(options = {}) {
|
|
|
975
975
|
const identityDir = (0, node_path_1.join)(stateDir, "identity");
|
|
976
976
|
app.get("/identity", (req, res) => {
|
|
977
977
|
try {
|
|
978
|
-
|
|
979
|
-
//
|
|
980
|
-
//
|
|
981
|
-
//
|
|
982
|
-
|
|
983
|
-
if (r.status === 200) {
|
|
984
|
-
(0, memory_instructions_js_1.injectMemorySection)(r.body, memoryInstructionsEnabled);
|
|
985
|
-
}
|
|
978
|
+
// serveIdentityBody (#192 + #313): the ONE composition — synthetic
|
|
979
|
+
// product-owned `memory` section, then the SECTION_PRECEDENCE wire
|
|
980
|
+
// order. Shared with GET /context and the MCP hicortex_identity tool so
|
|
981
|
+
// every surface serves byte-identical ordering.
|
|
982
|
+
const r = (0, identity_store_js_1.serveIdentityBody)((0, identity_store_js_1.handleIdentityGet)(identityDir, identityClients, req.query, identityAgents), memoryInstructionsEnabled);
|
|
986
983
|
res.status(r.status).json(r.body);
|
|
987
984
|
}
|
|
988
985
|
catch (err) {
|
|
@@ -1013,10 +1010,9 @@ async function startServer(options = {}) {
|
|
|
1013
1010
|
// difference in behaviour, only the URL.
|
|
1014
1011
|
app.get("/context", (req, res) => {
|
|
1015
1012
|
try {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
}
|
|
1013
|
+
// Same serveIdentityBody composition as GET /identity — the alias
|
|
1014
|
+
// serves byte-equal behaviour by construction.
|
|
1015
|
+
const r = (0, identity_store_js_1.serveIdentityBody)((0, identity_store_js_1.handleIdentityGet)(identityDir, identityClients, req.query, identityAgents), memoryInstructionsEnabled);
|
|
1020
1016
|
res.status(r.status).json(r.body);
|
|
1021
1017
|
}
|
|
1022
1018
|
catch (err) {
|
package/dist/prompts.js
CHANGED
|
@@ -130,6 +130,8 @@ EXTRACT into this markdown format:
|
|
|
130
130
|
|
|
131
131
|
### Project State Changes
|
|
132
132
|
- [D] [SUBJECT]: [what changed], [from → to] (${date})
|
|
133
|
+
(Durable shifts only — the model/tool/approach the project now uses. A
|
|
134
|
+
status flip or counter change is NEVER-RECORD ephemera, not a state change)
|
|
133
135
|
|
|
134
136
|
### Key Entities & Relationships
|
|
135
137
|
- [K] [entity A] → [relationship] → [entity B] (${date})
|
|
@@ -179,6 +181,23 @@ label, a sentiment ("Strong Negative"), or "User rejected…" is unfindable —
|
|
|
179
181
|
matches every emotionally-similar prompt and no topically-relevant one. Front-load
|
|
180
182
|
the subject; put reaction, intensity and reasoning AFTER it.
|
|
181
183
|
|
|
184
|
+
NEVER-RECORD — ephemera gate (critical):
|
|
185
|
+
Every candidate must pass one test: will it still be TRUE and still MATTER in 3 months?
|
|
186
|
+
Content whose entire value is a state that expires is NEVER recorded —
|
|
187
|
+
do not score it lower and write it anyway: OMIT it. A closed category of never-record ephemera:
|
|
188
|
+
- issue/PR/epic/merge status: "PR #173 merged", "Epic 2 CLOSED — all children merged"
|
|
189
|
+
- version/deploy/test-count statistics: "v0.16.0 deployed to rc dist-tag",
|
|
190
|
+
"Test suite grew 616→749", "Main branch updated to <sha>"
|
|
191
|
+
- session bookkeeping/outcomes: "Session closure: nothing remains to do",
|
|
192
|
+
todo deferrals ("parked until next week"), sync/replay states
|
|
193
|
+
- transient readings/snapshots: "disk usage snapshot: 84% at 14:20",
|
|
194
|
+
"uptime counter passed 40 days"
|
|
195
|
+
The durable part of the same event may still qualify — the CHOICE a change
|
|
196
|
+
embodies ("standardize on model X", user-confirmed) is [D], a configuration
|
|
197
|
+
that holds going forward is [K]; the version bump, merge, or count itself never is.
|
|
198
|
+
If EVERY item in the transcript is never-record ephemera, output ONLY:
|
|
199
|
+
"NO_EXTRACT" — zero memories is the correct result for a pure-status segment.
|
|
200
|
+
|
|
182
201
|
RULES:
|
|
183
202
|
- Extract MAX 20 items total (quality over quantity)
|
|
184
203
|
- Use EXACT names/versions/paths/numbers as they appear in the transcript —
|
|
@@ -187,7 +206,8 @@ RULES:
|
|
|
187
206
|
- Each must be useful if recalled in a future session
|
|
188
207
|
- Skip: routine code edits, standard tool usage, trivial fixes
|
|
189
208
|
- Include: architectural decisions, debugging breakthroughs, user preferences,
|
|
190
|
-
tool configurations, API discoveries, project milestones
|
|
209
|
+
tool configurations, API discoveries, durable project milestones (a status
|
|
210
|
+
flip — shipped/merged/closed — is NEVER-RECORD ephemera, not a milestone)
|
|
191
211
|
- PRIORITIZE Corrections & Rejections — these are high-value signals for learning
|
|
192
212
|
what the user does NOT want. Even a single "no" or style correction is worth extracting.
|
|
193
213
|
- Strong language or profanity from the user is a high-intensity signal — it indicates
|
package/dist/types.d.ts
CHANGED
|
@@ -399,6 +399,20 @@ export interface HicortexConfig {
|
|
|
399
399
|
* leaner system prompts.
|
|
400
400
|
*/
|
|
401
401
|
lessonsLimit?: number;
|
|
402
|
+
/**
|
|
403
|
+
* Default project name for the OpenClaw plugin (#316, Hermes `default_project`
|
|
404
|
+
* parity): sent as the `project` fallback on /recall-index, the pre-0.14
|
|
405
|
+
* /search fallback, and the search/recent/ingest tools whenever the gateway
|
|
406
|
+
* supplies no project. Absent ⇒ no scope sent.
|
|
407
|
+
*/
|
|
408
|
+
defaultProject?: string;
|
|
409
|
+
/**
|
|
410
|
+
* Max memories per recall on the OpenClaw plugin's legacy /search fallback
|
|
411
|
+
* (pre-0.14 servers, #316). Default 8. Does NOT size the pushed
|
|
412
|
+
* /recall-index — that is server config (`recallMaxItems`); the server
|
|
413
|
+
* accepts no client limit.
|
|
414
|
+
*/
|
|
415
|
+
recallLimit?: number;
|
|
402
416
|
/**
|
|
403
417
|
* Soft cap on the memory corpus (default 10000). When the corpus exceeds this,
|
|
404
418
|
* the nightly's capacity-eviction stage (#245) removes the lowest-
|
|
@@ -123,22 +123,38 @@ def _title_case_section(name: str) -> str:
|
|
|
123
123
|
return " ".join(w[:1].upper() + w[1:] for w in words)
|
|
124
124
|
|
|
125
125
|
|
|
126
|
+
# #313 scope labels — mirror of the TS ``SECTION_LABELS`` in
|
|
127
|
+
# identity-store.ts (keep in sync). "Global rules" marks the section as
|
|
128
|
+
# fleet-wide; unknown section names fall back to title-case.
|
|
129
|
+
_SECTION_LABELS = {
|
|
130
|
+
"agent_identity": "Agent identity",
|
|
131
|
+
"user": "User",
|
|
132
|
+
"rules": "Global rules",
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
126
136
|
def _order_section_names(names: Iterable[str]) -> List[str]:
|
|
127
|
-
"""Stable ordering
|
|
137
|
+
"""Stable ordering — the #313 precedence contract, mirroring the TS
|
|
138
|
+
``SECTION_PRECEDENCE`` (keep in sync): ``agent_identity`` (the agent's own
|
|
139
|
+
self + role conduct, per-agent only) first, then ``user`` (the principal),
|
|
140
|
+
then ``rules`` (fleet-wide house rules), then the rest alphabetically."""
|
|
128
141
|
names = list(names)
|
|
129
|
-
primaries = [p for p in ("user", "rules") if p in names]
|
|
130
|
-
rest = sorted(n for n in names if n not in ("user", "rules"))
|
|
142
|
+
primaries = [p for p in ("agent_identity", "user", "rules") if p in names]
|
|
143
|
+
rest = sorted(n for n in names if n not in ("agent_identity", "user", "rules"))
|
|
131
144
|
return primaries + rest
|
|
132
145
|
|
|
133
146
|
|
|
134
147
|
def _render_context_block(sections: Dict[str, Any]) -> str:
|
|
135
|
-
"""Render the ``## Identity`` block, or "" when every section is blank.
|
|
148
|
+
"""Render the ``## Identity`` block, or "" when every section is blank.
|
|
149
|
+
Headings use the #313 scope labels (``_SECTION_LABELS``); unknown sections
|
|
150
|
+
fall back to title-case."""
|
|
136
151
|
body_parts: List[str] = []
|
|
137
152
|
for name in _order_section_names(sections.keys()):
|
|
138
153
|
body = sections.get(name)
|
|
139
154
|
if not isinstance(body, str) or not body.strip():
|
|
140
155
|
continue
|
|
141
|
-
|
|
156
|
+
label = _SECTION_LABELS.get(name) or _title_case_section(name)
|
|
157
|
+
body_parts.extend([f"### {label}", "", body.strip()])
|
|
142
158
|
if not body_parts:
|
|
143
159
|
return ""
|
|
144
160
|
return "\n".join(["## Identity", "", *body_parts])
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "hicortex",
|
|
3
3
|
"name": "Hicortex — Long-term Memory That Learns",
|
|
4
4
|
"description": "Your agents remember past decisions, avoid repeated mistakes, and get smarter every day. Nightly reflection generates actionable lessons that automatically update agent behavior.",
|
|
5
|
-
"version": "0.19.
|
|
5
|
+
"version": "0.19.2",
|
|
6
6
|
"kind": "lifecycle",
|
|
7
7
|
"skills": ["./skills/hicortex-memory"],
|
|
8
8
|
"configSchema": {
|
|
@@ -17,9 +17,14 @@
|
|
|
17
17
|
"type": "string",
|
|
18
18
|
"description": "Bearer token for the Hicortex server. Localhost bypasses auth automatically. Required for remote servers — use the authToken from ~/.hicortex/config.json on the server."
|
|
19
19
|
},
|
|
20
|
-
"
|
|
20
|
+
"defaultProject": {
|
|
21
21
|
"type": "string",
|
|
22
|
-
"description": "
|
|
22
|
+
"description": "Optional default project name scoping recall, search, and ingest when the gateway supplies no project (Hermes default_project parity)."
|
|
23
|
+
},
|
|
24
|
+
"recallLimit": {
|
|
25
|
+
"type": "number",
|
|
26
|
+
"default": 8,
|
|
27
|
+
"description": "Max memories per recall on the pre-0.14 /search fallback (default 8). The pushed recall index is sized by SERVER config (recallMaxItems) — the server accepts no client limit."
|
|
23
28
|
}
|
|
24
29
|
},
|
|
25
30
|
"required": []
|
|
@@ -34,10 +39,13 @@
|
|
|
34
39
|
"sensitive": true,
|
|
35
40
|
"placeholder": "Required for remote servers"
|
|
36
41
|
},
|
|
37
|
-
"
|
|
38
|
-
"label": "
|
|
39
|
-
"placeholder": "
|
|
40
|
-
|
|
42
|
+
"defaultProject": {
|
|
43
|
+
"label": "Default Project",
|
|
44
|
+
"placeholder": "Optional — scopes recall/ingest when the gateway sends no project"
|
|
45
|
+
},
|
|
46
|
+
"recallLimit": {
|
|
47
|
+
"label": "Recall Limit",
|
|
48
|
+
"placeholder": "8"
|
|
41
49
|
}
|
|
42
50
|
}
|
|
43
51
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamaze/hicortex",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.2",
|
|
4
4
|
"description": "Persistent agent identity for AI agents \u2014 a hand-edited identity layer, nightly-distilled experience, and lessons injected every session, shared across your whole fleet. Works with Hermes, OpenClaw, Claude Code, and Pi.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|