myelinate 0.2.0__tar.gz

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 (36) hide show
  1. myelinate-0.2.0/LICENSE +21 -0
  2. myelinate-0.2.0/PKG-INFO +311 -0
  3. myelinate-0.2.0/README.md +271 -0
  4. myelinate-0.2.0/pyproject.toml +80 -0
  5. myelinate-0.2.0/pyproject.toml.orig +74 -0
  6. myelinate-0.2.0/src/myelinate/__init__.py +8 -0
  7. myelinate-0.2.0/src/myelinate/adapters/__init__.py +0 -0
  8. myelinate-0.2.0/src/myelinate/adapters/generic.py +98 -0
  9. myelinate-0.2.0/src/myelinate/adapters/maf.py +135 -0
  10. myelinate-0.2.0/src/myelinate/cli.py +94 -0
  11. myelinate-0.2.0/src/myelinate/client.py +177 -0
  12. myelinate-0.2.0/src/myelinate/config.py +184 -0
  13. myelinate-0.2.0/src/myelinate/core.py +138 -0
  14. myelinate-0.2.0/src/myelinate/db.py +333 -0
  15. myelinate-0.2.0/src/myelinate/embeddings.py +46 -0
  16. myelinate-0.2.0/src/myelinate/engine.py +588 -0
  17. myelinate-0.2.0/src/myelinate/evolution.py +183 -0
  18. myelinate-0.2.0/src/myelinate/experiments.py +92 -0
  19. myelinate-0.2.0/src/myelinate/gateway/__init__.py +0 -0
  20. myelinate-0.2.0/src/myelinate/gateway/app.py +572 -0
  21. myelinate-0.2.0/src/myelinate/gateway/auth.py +155 -0
  22. myelinate-0.2.0/src/myelinate/gateway/mcp_server.py +107 -0
  23. myelinate-0.2.0/src/myelinate/governance.py +368 -0
  24. myelinate-0.2.0/src/myelinate/learning.py +208 -0
  25. myelinate-0.2.0/src/myelinate/llm.py +88 -0
  26. myelinate-0.2.0/src/myelinate/maintenance.py +152 -0
  27. myelinate-0.2.0/src/myelinate/memory.py +164 -0
  28. myelinate-0.2.0/src/myelinate/models.py +246 -0
  29. myelinate-0.2.0/src/myelinate/otel.py +260 -0
  30. myelinate-0.2.0/src/myelinate/prompts.py +180 -0
  31. myelinate-0.2.0/src/myelinate/py.typed +0 -0
  32. myelinate-0.2.0/src/myelinate/retrieval.py +131 -0
  33. myelinate-0.2.0/src/myelinate/safety.py +58 -0
  34. myelinate-0.2.0/src/myelinate/skills.py +301 -0
  35. myelinate-0.2.0/src/myelinate/telemetry.py +62 -0
  36. myelinate-0.2.0/src/myelinate/worker.py +145 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 notaaaronfr and Myelinate contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,311 @@
1
+ Metadata-Version: 2.4
2
+ Name: myelinate
3
+ Version: 0.2.0
4
+ Summary: Self-improving skills and memory for any AI agent framework, with governance built in
5
+ Keywords: ai-agents,self-improving,agent-memory,skills,mcp,openclaw,microsoft-agent-framework,llm,continual-learning
6
+ Author: arrondavide
7
+ Author-email: arrondavide <arrondavide@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Framework :: FastAPI
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Dist: aiosqlite>=0.22.1
16
+ Requires-Dist: anthropic>=1.15.0
17
+ Requires-Dist: asyncpg>=0.32.0
18
+ Requires-Dist: fastapi>=0.143.2
19
+ Requires-Dist: httpx>=0.28.1
20
+ Requires-Dist: mcp>=2.3.0
21
+ Requires-Dist: opentelemetry-proto>=1.45.1
22
+ Requires-Dist: prometheus-client>=0.26.0
23
+ Requires-Dist: pydantic>=2.14.1
24
+ Requires-Dist: pydantic-settings>=2.16.0
25
+ Requires-Dist: pyjwt[crypto]>=2.15.1
26
+ Requires-Dist: sqlalchemy[asyncio]>=2
27
+ Requires-Dist: structlog>=26.1.0
28
+ Requires-Dist: uvicorn[standard]>=0.54.0
29
+ Requires-Dist: agent-framework-core>=1.22.0 ; extra == 'maf'
30
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.45.1 ; extra == 'otel'
31
+ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.66b1 ; extra == 'otel'
32
+ Requires-Dist: opentelemetry-sdk>=1.45.1 ; extra == 'otel'
33
+ Requires-Python: >=3.12
34
+ Project-URL: Homepage, https://github.com/notaaaronfr/myelinate
35
+ Project-URL: Repository, https://github.com/notaaaronfr/myelinate
36
+ Project-URL: Issues, https://github.com/notaaaronfr/myelinate/issues
37
+ Provides-Extra: maf
38
+ Provides-Extra: otel
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Myelinate
42
+
43
+ [![CI](https://github.com/notaaaronfr/myelinate/actions/workflows/ci.yml/badge.svg)](https://github.com/notaaaronfr/myelinate/actions/workflows/ci.yml)
44
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
45
+ ![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue)
46
+ [![Docs](https://img.shields.io/badge/docs-notaaaronfr.github.io%2Fmyelinate-6f42c1)](https://notaaaronfr.github.io/myelinate/)
47
+
48
+ **Self-improving skills and memory for any AI agent framework, with governance built in.**
49
+
50
+ **[Documentation](https://notaaaronfr.github.io/myelinate/)** ·
51
+ [Quickstart](https://notaaaronfr.github.io/myelinate/getting-started/quickstart/) ·
52
+ [Integrations](https://notaaaronfr.github.io/myelinate/integrations/overview/) ·
53
+ [Deployment](https://notaaaronfr.github.io/myelinate/deployment/kubernetes/) ·
54
+ [API reference](https://notaaaronfr.github.io/myelinate/reference/api/)
55
+
56
+ > *Myelin* is the sheath the brain builds around pathways that get used, and that work, so they fire faster and more
57
+ > reliably. Myelinate does the same for agents: rules that help get reinforced, rules that hurt get corrected or retired,
58
+ > and nothing changes without evidence.
59
+
60
+ A drop-in component that gives **any** agent framework a self-improvement loop: learned skills, persistent memory,
61
+ reflection, and skill evolution. Every change is governed, measured and reversible.
62
+
63
+ You attach it to Microsoft Agent Framework, OpenClaw, LangGraph, CrewAI, ADK or anything else. The agent stays
64
+ in its own framework and makes two calls per run: **recall** before it and **record** after it. Frameworks that
65
+ emit OpenTelemetry need no code at all.
66
+
67
+ The design combines the strongest published mechanisms (ACE, Kayba ACE, GEPA, SkillOpt, Trace2Skill, WikiSkill,
68
+ ReasoningBank, Mem0, Zep/Graphiti, Honcho, Hermes Agent, Letta, LangMem, Voyager, AWM). It adds what none of them
69
+ have: **live canary rollout, a holdout control group that measures causal lift, and enterprise governance**.
70
+
71
+ ```
72
+ agent (MAF · OpenClaw · LangGraph · CrewAI · ADK · custom) OTel GenAI / OpenInference traces
73
+ │ recall ──────────────┐ ┌──────────── record │ (zero-code)
74
+ ▼ ▼ ▼ ▼
75
+ ┌──────────────────────────── Myelinate (REST · MCP · OTLP) ────────────────────────────┐
76
+ │ authN/Z → tenant isolation → rate limit → audit │
77
+ │ RECALL hybrid BM25+dense (RRF) × skill posterior → MMR → canary arm / holdout → stable, cacheable │
78
+ │ RECORD PII redaction → usage + reward credit (Beta posteriors: skills, canaries, holdout) │
79
+ │ durable debounced jobs (multi-replica safe, budgets) │
80
+ │ REFLECT outcome signal (verifier > feedback > label > LLM judge) → per-run diagnosis → │
81
+ │ helpful/harmful tags on injected rules → memory reconcile → CURATE bounded delta ops │
82
+ │ EVOLVE GEPA: Pareto parents, minibatch pre-gate, strict held-out gate, rejected-edit buffer │
83
+ │ CURATE dedup-merge (KEEP remembered), stale→archived lifecycle, evidence-based nomination │
84
+ │ GOVERN changeset → safety scan + lint → risk tier → policy/human → CANARY on live traffic → │
85
+ │ promote/reject by posterior → immutable version → rollback │
86
+ └─────────────────────── SQLite (dev) · PostgreSQL (prod) · Prometheus · OpenTelemetry ─────────────┘
87
+ ```
88
+
89
+ ## Why it's better than each alternative
90
+
91
+ | | Hermes Agent | Kayba ACE | ACE paper | LangMem | Letta | Mem0 / Zep | Agent Lightning | **This gateway** |
92
+ |---|---|---|---|---|---|---|---|---|
93
+ | Works inside *your* framework | no (own agent) | some | no | LangChain | no (own harness) | yes (memory only) | yes (training) | **yes: REST, MCP, OTLP, adapters** |
94
+ | Learned procedures (skills) | yes | yes | playbook | prompt rewrite | yes | no | no | **yes, as rule-level bullets in SKILL.md** |
95
+ | Edits are typed deltas, not rewrites | partly | yes | yes | no | no | n/a | n/a | **yes, bounded per changeset** |
96
+ | Rule-level helpful/harmful credit | no | yes | yes | no | no | no | per-call | **yes, plus a posterior per skill** |
97
+ | Learns only from reliable signals | no | no | no | no | partly | no | needs reward | **evidence gating + judge confidence** |
98
+ | Optimises underperforming skills | GEPA (offline PR) | no | no | yes | no | no | RL/APO | **GEPA + strict gate + rejected buffer** |
99
+ | Validated on live traffic before full rollout | no | no | no | no | no | no | no | **Bayesian canary** |
100
+ | Measures causal lift | no | no | no | no | no | no | no | **holdout control group** |
101
+ | Memory with contradiction handling | char-limited files | no | no | update/delete | git files | yes (Zep: bi-temporal) | no | **reconcile + bi-temporal + profile cards** |
102
+ | Approval, versions, rollback, audit | approval gate, ledger | no | no | no | git | history | no | **changesets, versions, rollback, audit log** |
103
+ | Multi-tenant, RBAC, SSO, erasure, budgets | no | no | no | no | partly | platform | no | **yes** |
104
+
105
+ ## What each mechanism is, and where it comes from
106
+
107
+ **Knowledge model**
108
+ - *Skills are sets of atomic bullets* ("When <trigger>, <action>", 15–50 words) grouped as steps, pitfalls,
109
+ heuristics, verification, snippets and notes, and exported as agentskills.io `SKILL.md`.
110
+ ACE's ablation: delta updates instead of whole rewrites were worth **+17 vs +3.6 points**. Rewriting causes
111
+ "context collapse" (18k tokens fell to 122 and accuracy dropped below baseline).
112
+ - *Bounded edits per changeset* (SkillOpt's "textual learning rate"). Unbounded rewrites underperform.
113
+ - *Lint* blocks incident-diary-shaped rules (Hermes) and over-long rules. Rules must generalise, with names
114
+ replaced by placeholders, and a broad rule can replace narrow ones only with ≥3 instances across ≥2 tasks (Kayba).
115
+
116
+ **Signals and credit**
117
+ - *Outcome hierarchy*: verifier/tests > user feedback or correction > reported outcome > LLM self-judge
118
+ (ReasoningBank: judge accuracy of about 73% was enough).
119
+ **Evidence gating**: runs without a reliable signal can add memories but never change skills.
120
+ ACE and Dynamic Cheatsheet both fell *below baseline* when learning from unreliable feedback. Letta found
121
+ verifier feedback added **+6.7 points** on top of trajectory-only learning.
122
+ - *Reflector* diagnoses each run, successes included (ACE, Trace2Skill), and tags only the rules that were
123
+ actually injected (Kayba). Optional citation mode (`[b-xxxxxxxx]`) gives sharper attribution.
124
+ - *Beta posteriors* on every skill and canary arm, with fractional, re-creditable rewards (feedback after a judged
125
+ outcome replaces the old credit instead of double counting).
126
+
127
+ **Improvement**
128
+ - *Curator* returns only ops for what is **missing or wrong**. An empty list is the expected answer for most batches.
129
+ Previously rejected edits are shown to it so they aren't proposed again (SkillOpt's buffer).
130
+ - *Evolution*:
131
+ - GEPA Pareto parent selection (+12.4 vs +6.1 for select-best in GEPA's ablation).
132
+ - A minibatch pre-gate (b=3) before the expensive held-out evaluation.
133
+ - A strict gate: ties lose, and the improvement must clear a margin.
134
+ - A brevity guard that rejects children dropping more than 30% of the rules.
135
+ - The output is a reviewable net diff.
136
+ - *Canary*: a changed proven skill is served beside the incumbent by Thompson sampling with an exploration floor.
137
+ Assignment is sticky per session. The canary auto-promotes at P(better) ≥ 0.95 and auto-rejects at ≤ 0.05 or when
138
+ the budget runs out. This guards against the limit every paper names: offline judges are imperfect.
139
+ - *Holdout*: by default 5% of runs get no learned skills, and the would-be-served skills are recorded so the
140
+ comparison is like for like. `/insights` reports the lift with a credible interval: the ROI number.
141
+
142
+ **Memory**
143
+ - *Reconcile* each candidate against its nearest memories with ADD / UPDATE / SUPERSEDE / NOOP (Mem0). Exact
144
+ duplicates cost no LLM call.
145
+ - *Bi-temporal*: superseded facts get `invalid_at` and `superseded_by` and are never deleted by learning (Zep).
146
+ `as_of` gives point-in-time recall for audits.
147
+ - *Profile cards* per user, rebuilt in the background (Honcho peer card, Hermes USER.md). The current user's
148
+ preferences always apply.
149
+
150
+ **Upkeep**
151
+ - *Dedup* proposes merges for near-duplicate rules. KEEP decisions are remembered and merges sum the evidence counters (ACE, Kayba).
152
+ - *Lifecycle* moves unused skills active → stale (14 d) → archived (30 d). Nothing is deleted, and pinned skills are exempt (Hermes curator).
153
+ - *Nomination*: poor posteriors or rules that keep being tagged harmful queue an evolution run. Counters nominate
154
+ but never delete; Kayba removed auto-delete at harmful≥3 for good reason.
155
+
156
+ **Retrieval**
157
+ - BM25 plus optional embeddings, fused with RRF, with the skill posterior as a prior, then MMR for diversity (Zep, Mem0 2026).
158
+ - Progressive disclosure: the top-k skills are injected in full and the rest appear as a name index loaded with `skill_view` (Hermes).
159
+ - Injected text is ordered deterministically, so the prompt prefix caches (ACE served 91.8% of input from cache).
160
+
161
+ ## Quick start
162
+
163
+ ```bash
164
+ uv sync --extra maf
165
+ echo "ANTHROPIC_API_KEY=..." >> .env # learning model (default claude-opus-5-5); read from env or .env
166
+ MYELINATE_ENV=dev uv run myelinate serve --port 8080 # dev: no credentials, tenant "dev"
167
+ open http://localhost:8080/docs
168
+ ```
169
+
170
+ Without `MYELINATE_ENV=dev` the gateway is secure by default: it refuses to start without a bootstrap admin key
171
+ or OIDC configuration.
172
+
173
+ Production: `cp .env.example .env`, edit it, then `docker compose --env-file .env -f deploy/docker-compose.yml up -d`. That runs the gateway, a
174
+ worker pool and Postgres. Mint scoped keys with `POST /v1/admin/api-keys`.
175
+
176
+ ## Plugging in
177
+
178
+ **Microsoft Agent Framework**, as a context provider:
179
+ ```python
180
+ learner = SelfLearningProvider(GatewayClient("https://learner.internal", api_key="myl_..."), agent_id="support-bot",
181
+ verify_fn=lambda ctx: Verification(passed=ticket_resolved(ctx))) # optional ground truth
182
+ agent = Agent(client=chat_client, instructions="...", context_providers=[learner])
183
+ ```
184
+
185
+ **OpenClaw**, as a plugin ([adapters/openclaw/](adapters/openclaw/)): the `before_prompt_build` hook injects learned
186
+ context, `agent_end` records the run, and it adds the tools `skill_view` (credited to the turn), `remember`, and
187
+ `rate_last_turn` (with a correction).
188
+
189
+ **Zero code** for any framework that emits OpenTelemetry GenAI spans (MAF, ADK, Strands, Pydantic AI, OpenClaw
190
+ diagnostics-otel, or LangGraph/CrewAI through OpenInference):
191
+ ```bash
192
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://learner.internal/v1/traces
193
+ OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf # http/json works too; gzip is accepted
194
+ OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer myl_...,X-Agent-Id=support-bot"
195
+ ```
196
+ Spans of one trace that arrive in separate exports are merged into one episode. `gen_ai.skill.name` spans credit
197
+ skills automatically. Set the span attributes `myelinate.outcome` /
198
+ `myelinate.verification.passed` to add labels. Recall still needs one call, or the MCP tool, for the agent to
199
+ *use* what was learned.
200
+
201
+ **Any MCP client** (Claude, Hermes, Cursor...): `https://learner.internal/mcp`, with the tools `recall`, `skill_view`,
202
+ `remember`, `record_episode`, `feedback` and `ask`.
203
+
204
+ **Anything else** (LangGraph, CrewAI, OpenAI Agents SDK...):
205
+ ```python
206
+ async with learner.turn(task, user_id="u1") as t:
207
+ out = await run_my_agent(system=BASE + t.instructions, task=task)
208
+ t.add_message("assistant", out)
209
+ t.verify(passed=tests_ok, details=test_log)
210
+ ```
211
+
212
+ **Bring existing skills**: `POST /v1/skills/import` with any SKILL.md (Anthropic, Hermes, agentskills.io). Bulk-import
213
+ history with `POST /v1/episodes:batch`, then `POST /v1/agents/{id}/replay` to warm-start learning offline (ACE's
214
+ offline warm-up lifted its online score from 56.1 to 59.5).
215
+
216
+ ## API
217
+
218
+ | Area | Endpoints |
219
+ |---|---|
220
+ | Loop | `POST /v1/recall`, `POST /v1/episodes`, `POST /v1/episodes:batch`, `POST /v1/feedback`, `POST /v1/traces` (OTLP), `POST /v1/ask` |
221
+ | Skills | `GET /v1/skills`, `GET /v1/skills/{ref}`, `GET …/SKILL.md`, `GET …/versions`, `POST /v1/skills`, `POST /v1/skills/import`, `POST …/rollback`, `POST …/pin`, `POST …/evolve` |
222
+ | Memory | `GET|POST /v1/memories` (`as_of`, `include_history`), `POST …/approve`, `DELETE /v1/memories/{id}`, `GET /v1/profiles/{agent}/{user}` |
223
+ | Governance | `GET /v1/changesets`, `POST /v1/changesets/{id}/review` (`skip_canary`), `POST /v1/agents/{id}/reflect` / `curate` / `replay`, `GET /v1/agents/{id}/insights`, `GET /v1/agents/{id}/export` (JSONL for RL / fine-tuning) |
224
+ | Admin | `POST|DELETE /v1/admin/api-keys`, `GET /v1/admin/audit`, `GET /v1/admin/usage`, `DELETE /v1/admin/users/{id}` |
225
+ | Ops | `/healthz`, `/readyz`, `/metrics`, `/mcp`, `/docs` |
226
+
227
+ ## Enterprise controls
228
+
229
+ - **Identity:** tenant API keys (hashed, revocable) or OIDC (Entra ID, Okta, Auth0, Keycloak). Scopes are `learn`, `review` and `admin`.
230
+ - **Isolation:** every query is tenant-scoped. Knowledge is scoped per agent, with tenant-shared skills under `agent_id="*"`.
231
+ - **Safety:**
232
+ - PII and secrets are redacted before storage.
233
+ - Every changeset is scanned for secrets, prompt injection and oversize content. Flagged changes never auto-apply.
234
+ - Risk tiers: additive = low, edits = medium, removals and routing changes = high (always human).
235
+ - **Change control:**
236
+ - Immutable version snapshots and optimistic concurrency (stale changesets fail instead of clobbering).
237
+ - Canary before full rollout, and one-call rollback.
238
+ - The rejected-change history is kept and learned from.
239
+ - **Privacy:**
240
+ - Right to erasure.
241
+ - Episode retention (`myelinate purge`).
242
+ - Hard memory delete for data-subject requests. Learning itself never hard-deletes.
243
+ - **Cost:** a per-tenant daily token budget. Over-budget jobs are deferred, not failed. Usage is broken down by purpose for chargeback.
244
+ - **Reliability:**
245
+ - A durable job queue with leases, heartbeats, retries and debounce, safe across replicas. Only one job per agent
246
+ reflects at a time.
247
+ - Atomic SQL counter updates, so concurrent runs never lose credit.
248
+ - Idempotency keys (set by the SDKs and derived from the OTel trace id), so retried uploads never double count.
249
+ - Adapters fail open, so a gateway outage never breaks the agent.
250
+ - Canaries that can't reach a verdict expire and keep the incumbent. Queued changes are re-evaluated, never
251
+ silently rebased.
252
+ - **Observability:** Prometheus metrics, including learning-cost and canary-verdict counters. JSON logs carry request and tenant IDs, and OTel tracing is available.
253
+
254
+ ## Layout
255
+
256
+ ```
257
+ src/myelinate/
258
+ engine.py facade: recall / record / credit / feedback / ask / insights / export
259
+ learning.py outcome signal, reflector, evidence gating, curator
260
+ evolution.py GEPA-style evolution with gates
261
+ governance.py changesets, policy, canary experiments, apply, versions, rollback
262
+ memory.py reconcile, bi-temporal store, profile cards
263
+ maintenance.py dedup, lifecycle, nomination, profile refresh
264
+ skills.py delta ops, simulation, diff, SKILL.md render/parse, lint
265
+ experiments.py Beta posteriors, Thompson sampling, lift
266
+ retrieval.py BM25 + dense RRF + MMR embeddings.py optional /v1/embeddings client
267
+ otel.py OTLP → episodes prompts.py role prompts + strict schemas
268
+ core.py metered LLM, budgets, jobs, audit worker.py durable job worker
269
+ gateway/ FastAPI app, auth/RBAC, MCP server adapters/ maf.py, generic.py
270
+ adapters/openclaw TypeScript plugin + reusable TS client
271
+ tests/ 60 tests: loop, gating, tagging, canary, GEPA, memory, dedup, lift, OTel, import, auth, MCP, budget,
272
+ concurrency, idempotency, SDK request shape, regressions
273
+ ```
274
+
275
+ ## Verification status
276
+
277
+ | Check | Result |
278
+ |---|---|
279
+ | Test suite (60 tests) | Passes on SQLite and on PostgreSQL 17 (`MYELINATE_TEST_DATABASE_URL=postgresql+asyncpg://… uv run pytest`), with 5 repeated runs and no flakes |
280
+ | Microsoft Agent Framework adapter | Runs inside a real `agent_framework` 1.22 `Agent` (test) |
281
+ | OpenClaw plugin | Type-checks against the real `openclaw@2026.10.4` SDK. Installs, enables, passes `plugins doctor`, and its hooks and tools register in the real runtime (`inspect --runtime`). **Real agent turns with `anthropic/claude-opus-5-5` close the loop:** (1) the agent followed an injected skill exactly; (2) a user correction given in chat reached the gateway through `rate_last_turn`; (3) Claude reflected and proposed a rule update, which policy held for review; (4) after approval, a brand-new session produced the corrected format |
282
+ | Docker | `docker build` succeeds (415 MB, non-root). `docker compose` (gateway, 2 workers, Postgres) reaches healthy on every service. A failed production migration recorded via the API was learned by a worker replica with real Claude into a correct `postgres-schema-migration` skill stored in Postgres |
283
+ | Claude request path | Real Anthropic SDK (1.15) with a mocked transport: request shape, structured output, fallbacks, usage metering, refusal / max_tokens / 429 / 400 handling. Every schema is checked to be strict |
284
+ | **Live Claude (`claude-opus-5-5`)** | Full pipeline against the real API: outcome judging, reflection, curation (a skill with 3 well-formed rules from one failed deploy), memory reconciliation, learning from a user correction, GEPA evolution (one run accepted at judge 0.46 → 0.80, one rejected for gaining too little), dedup merge, profile card, ask. About $0.44 upper bound for the whole run (31 calls) |
285
+ | Production mode | The built package boots with `MYELINATE_ENV=prod` on PostgreSQL. Verified: auth, scopes, recall, idempotent record, input limits, MCP tool calls, OTLP ingestion, audit, metrics |
286
+ | Static analysis | ruff clean. Pyright reports only known false positives (FastAPI `Annotated` dependencies, SQLAlchemy `rowcount`) |
287
+
288
+ **Not covered here:** load and performance testing, Kubernetes manifests (only Compose ships), and Entra ID / Okta SSO
289
+ against a real identity provider (JWT validation is implemented, but was not tested against one).
290
+
291
+ ## Honest limits
292
+
293
+ - **Learning quality is bounded by signal quality.** Wire `verify_fn` / `t.verify()` / feedback to real checks where
294
+ you can. Without them the system stays conservative (memories only).
295
+ - **The LLM judge used in evolution is a proxy.** That is why changed proven skills are canaried on live traffic. Canaries
296
+ need traffic: with few runs per skill, keep `MYELINATE_AUTO_APPROVE_MEDIUM_RISK=false` and review.
297
+ - **Migrations.** Tables are created at startup. Add Alembic before your first production schema change.
298
+ - **Scale.** Lexical retrieval over a few thousand skills per agent is fine. Beyond that, configure embeddings and move them
299
+ to pgvector. The rate limiter is per process; put a shared limiter in front of multiple replicas.
300
+ - **OTLP** is accepted over HTTP (protobuf or JSON, gzip or not). gRPC needs a Collector in front.
301
+ - **The OpenClaw plugin** targets `openclaw@2026.10.4` (Node ≥24.16 <25 or ≥26.1). Re-run `npx tsc` against newer
302
+ SDK versions when upgrading.
303
+
304
+ ## Contributing and security
305
+
306
+ Issues and pull requests are welcome. CI runs the test suite on SQLite and PostgreSQL, type-checks the OpenClaw plugin
307
+ and builds the Docker image. Please report vulnerabilities privately; see [SECURITY.md](SECURITY.md).
308
+
309
+ ## License
310
+
311
+ [MIT](LICENSE)
@@ -0,0 +1,271 @@
1
+ # Myelinate
2
+
3
+ [![CI](https://github.com/notaaaronfr/myelinate/actions/workflows/ci.yml/badge.svg)](https://github.com/notaaaronfr/myelinate/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
+ ![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue)
6
+ [![Docs](https://img.shields.io/badge/docs-notaaaronfr.github.io%2Fmyelinate-6f42c1)](https://notaaaronfr.github.io/myelinate/)
7
+
8
+ **Self-improving skills and memory for any AI agent framework, with governance built in.**
9
+
10
+ **[Documentation](https://notaaaronfr.github.io/myelinate/)** ·
11
+ [Quickstart](https://notaaaronfr.github.io/myelinate/getting-started/quickstart/) ·
12
+ [Integrations](https://notaaaronfr.github.io/myelinate/integrations/overview/) ·
13
+ [Deployment](https://notaaaronfr.github.io/myelinate/deployment/kubernetes/) ·
14
+ [API reference](https://notaaaronfr.github.io/myelinate/reference/api/)
15
+
16
+ > *Myelin* is the sheath the brain builds around pathways that get used, and that work, so they fire faster and more
17
+ > reliably. Myelinate does the same for agents: rules that help get reinforced, rules that hurt get corrected or retired,
18
+ > and nothing changes without evidence.
19
+
20
+ A drop-in component that gives **any** agent framework a self-improvement loop: learned skills, persistent memory,
21
+ reflection, and skill evolution. Every change is governed, measured and reversible.
22
+
23
+ You attach it to Microsoft Agent Framework, OpenClaw, LangGraph, CrewAI, ADK or anything else. The agent stays
24
+ in its own framework and makes two calls per run: **recall** before it and **record** after it. Frameworks that
25
+ emit OpenTelemetry need no code at all.
26
+
27
+ The design combines the strongest published mechanisms (ACE, Kayba ACE, GEPA, SkillOpt, Trace2Skill, WikiSkill,
28
+ ReasoningBank, Mem0, Zep/Graphiti, Honcho, Hermes Agent, Letta, LangMem, Voyager, AWM). It adds what none of them
29
+ have: **live canary rollout, a holdout control group that measures causal lift, and enterprise governance**.
30
+
31
+ ```
32
+ agent (MAF · OpenClaw · LangGraph · CrewAI · ADK · custom) OTel GenAI / OpenInference traces
33
+ │ recall ──────────────┐ ┌──────────── record │ (zero-code)
34
+ ▼ ▼ ▼ ▼
35
+ ┌──────────────────────────── Myelinate (REST · MCP · OTLP) ────────────────────────────┐
36
+ │ authN/Z → tenant isolation → rate limit → audit │
37
+ │ RECALL hybrid BM25+dense (RRF) × skill posterior → MMR → canary arm / holdout → stable, cacheable │
38
+ │ RECORD PII redaction → usage + reward credit (Beta posteriors: skills, canaries, holdout) │
39
+ │ durable debounced jobs (multi-replica safe, budgets) │
40
+ │ REFLECT outcome signal (verifier > feedback > label > LLM judge) → per-run diagnosis → │
41
+ │ helpful/harmful tags on injected rules → memory reconcile → CURATE bounded delta ops │
42
+ │ EVOLVE GEPA: Pareto parents, minibatch pre-gate, strict held-out gate, rejected-edit buffer │
43
+ │ CURATE dedup-merge (KEEP remembered), stale→archived lifecycle, evidence-based nomination │
44
+ │ GOVERN changeset → safety scan + lint → risk tier → policy/human → CANARY on live traffic → │
45
+ │ promote/reject by posterior → immutable version → rollback │
46
+ └─────────────────────── SQLite (dev) · PostgreSQL (prod) · Prometheus · OpenTelemetry ─────────────┘
47
+ ```
48
+
49
+ ## Why it's better than each alternative
50
+
51
+ | | Hermes Agent | Kayba ACE | ACE paper | LangMem | Letta | Mem0 / Zep | Agent Lightning | **This gateway** |
52
+ |---|---|---|---|---|---|---|---|---|
53
+ | Works inside *your* framework | no (own agent) | some | no | LangChain | no (own harness) | yes (memory only) | yes (training) | **yes: REST, MCP, OTLP, adapters** |
54
+ | Learned procedures (skills) | yes | yes | playbook | prompt rewrite | yes | no | no | **yes, as rule-level bullets in SKILL.md** |
55
+ | Edits are typed deltas, not rewrites | partly | yes | yes | no | no | n/a | n/a | **yes, bounded per changeset** |
56
+ | Rule-level helpful/harmful credit | no | yes | yes | no | no | no | per-call | **yes, plus a posterior per skill** |
57
+ | Learns only from reliable signals | no | no | no | no | partly | no | needs reward | **evidence gating + judge confidence** |
58
+ | Optimises underperforming skills | GEPA (offline PR) | no | no | yes | no | no | RL/APO | **GEPA + strict gate + rejected buffer** |
59
+ | Validated on live traffic before full rollout | no | no | no | no | no | no | no | **Bayesian canary** |
60
+ | Measures causal lift | no | no | no | no | no | no | no | **holdout control group** |
61
+ | Memory with contradiction handling | char-limited files | no | no | update/delete | git files | yes (Zep: bi-temporal) | no | **reconcile + bi-temporal + profile cards** |
62
+ | Approval, versions, rollback, audit | approval gate, ledger | no | no | no | git | history | no | **changesets, versions, rollback, audit log** |
63
+ | Multi-tenant, RBAC, SSO, erasure, budgets | no | no | no | no | partly | platform | no | **yes** |
64
+
65
+ ## What each mechanism is, and where it comes from
66
+
67
+ **Knowledge model**
68
+ - *Skills are sets of atomic bullets* ("When <trigger>, <action>", 15–50 words) grouped as steps, pitfalls,
69
+ heuristics, verification, snippets and notes, and exported as agentskills.io `SKILL.md`.
70
+ ACE's ablation: delta updates instead of whole rewrites were worth **+17 vs +3.6 points**. Rewriting causes
71
+ "context collapse" (18k tokens fell to 122 and accuracy dropped below baseline).
72
+ - *Bounded edits per changeset* (SkillOpt's "textual learning rate"). Unbounded rewrites underperform.
73
+ - *Lint* blocks incident-diary-shaped rules (Hermes) and over-long rules. Rules must generalise, with names
74
+ replaced by placeholders, and a broad rule can replace narrow ones only with ≥3 instances across ≥2 tasks (Kayba).
75
+
76
+ **Signals and credit**
77
+ - *Outcome hierarchy*: verifier/tests > user feedback or correction > reported outcome > LLM self-judge
78
+ (ReasoningBank: judge accuracy of about 73% was enough).
79
+ **Evidence gating**: runs without a reliable signal can add memories but never change skills.
80
+ ACE and Dynamic Cheatsheet both fell *below baseline* when learning from unreliable feedback. Letta found
81
+ verifier feedback added **+6.7 points** on top of trajectory-only learning.
82
+ - *Reflector* diagnoses each run, successes included (ACE, Trace2Skill), and tags only the rules that were
83
+ actually injected (Kayba). Optional citation mode (`[b-xxxxxxxx]`) gives sharper attribution.
84
+ - *Beta posteriors* on every skill and canary arm, with fractional, re-creditable rewards (feedback after a judged
85
+ outcome replaces the old credit instead of double counting).
86
+
87
+ **Improvement**
88
+ - *Curator* returns only ops for what is **missing or wrong**. An empty list is the expected answer for most batches.
89
+ Previously rejected edits are shown to it so they aren't proposed again (SkillOpt's buffer).
90
+ - *Evolution*:
91
+ - GEPA Pareto parent selection (+12.4 vs +6.1 for select-best in GEPA's ablation).
92
+ - A minibatch pre-gate (b=3) before the expensive held-out evaluation.
93
+ - A strict gate: ties lose, and the improvement must clear a margin.
94
+ - A brevity guard that rejects children dropping more than 30% of the rules.
95
+ - The output is a reviewable net diff.
96
+ - *Canary*: a changed proven skill is served beside the incumbent by Thompson sampling with an exploration floor.
97
+ Assignment is sticky per session. The canary auto-promotes at P(better) ≥ 0.95 and auto-rejects at ≤ 0.05 or when
98
+ the budget runs out. This guards against the limit every paper names: offline judges are imperfect.
99
+ - *Holdout*: by default 5% of runs get no learned skills, and the would-be-served skills are recorded so the
100
+ comparison is like for like. `/insights` reports the lift with a credible interval: the ROI number.
101
+
102
+ **Memory**
103
+ - *Reconcile* each candidate against its nearest memories with ADD / UPDATE / SUPERSEDE / NOOP (Mem0). Exact
104
+ duplicates cost no LLM call.
105
+ - *Bi-temporal*: superseded facts get `invalid_at` and `superseded_by` and are never deleted by learning (Zep).
106
+ `as_of` gives point-in-time recall for audits.
107
+ - *Profile cards* per user, rebuilt in the background (Honcho peer card, Hermes USER.md). The current user's
108
+ preferences always apply.
109
+
110
+ **Upkeep**
111
+ - *Dedup* proposes merges for near-duplicate rules. KEEP decisions are remembered and merges sum the evidence counters (ACE, Kayba).
112
+ - *Lifecycle* moves unused skills active → stale (14 d) → archived (30 d). Nothing is deleted, and pinned skills are exempt (Hermes curator).
113
+ - *Nomination*: poor posteriors or rules that keep being tagged harmful queue an evolution run. Counters nominate
114
+ but never delete; Kayba removed auto-delete at harmful≥3 for good reason.
115
+
116
+ **Retrieval**
117
+ - BM25 plus optional embeddings, fused with RRF, with the skill posterior as a prior, then MMR for diversity (Zep, Mem0 2026).
118
+ - Progressive disclosure: the top-k skills are injected in full and the rest appear as a name index loaded with `skill_view` (Hermes).
119
+ - Injected text is ordered deterministically, so the prompt prefix caches (ACE served 91.8% of input from cache).
120
+
121
+ ## Quick start
122
+
123
+ ```bash
124
+ uv sync --extra maf
125
+ echo "ANTHROPIC_API_KEY=..." >> .env # learning model (default claude-opus-5-5); read from env or .env
126
+ MYELINATE_ENV=dev uv run myelinate serve --port 8080 # dev: no credentials, tenant "dev"
127
+ open http://localhost:8080/docs
128
+ ```
129
+
130
+ Without `MYELINATE_ENV=dev` the gateway is secure by default: it refuses to start without a bootstrap admin key
131
+ or OIDC configuration.
132
+
133
+ Production: `cp .env.example .env`, edit it, then `docker compose --env-file .env -f deploy/docker-compose.yml up -d`. That runs the gateway, a
134
+ worker pool and Postgres. Mint scoped keys with `POST /v1/admin/api-keys`.
135
+
136
+ ## Plugging in
137
+
138
+ **Microsoft Agent Framework**, as a context provider:
139
+ ```python
140
+ learner = SelfLearningProvider(GatewayClient("https://learner.internal", api_key="myl_..."), agent_id="support-bot",
141
+ verify_fn=lambda ctx: Verification(passed=ticket_resolved(ctx))) # optional ground truth
142
+ agent = Agent(client=chat_client, instructions="...", context_providers=[learner])
143
+ ```
144
+
145
+ **OpenClaw**, as a plugin ([adapters/openclaw/](adapters/openclaw/)): the `before_prompt_build` hook injects learned
146
+ context, `agent_end` records the run, and it adds the tools `skill_view` (credited to the turn), `remember`, and
147
+ `rate_last_turn` (with a correction).
148
+
149
+ **Zero code** for any framework that emits OpenTelemetry GenAI spans (MAF, ADK, Strands, Pydantic AI, OpenClaw
150
+ diagnostics-otel, or LangGraph/CrewAI through OpenInference):
151
+ ```bash
152
+ OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://learner.internal/v1/traces
153
+ OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf # http/json works too; gzip is accepted
154
+ OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer myl_...,X-Agent-Id=support-bot"
155
+ ```
156
+ Spans of one trace that arrive in separate exports are merged into one episode. `gen_ai.skill.name` spans credit
157
+ skills automatically. Set the span attributes `myelinate.outcome` /
158
+ `myelinate.verification.passed` to add labels. Recall still needs one call, or the MCP tool, for the agent to
159
+ *use* what was learned.
160
+
161
+ **Any MCP client** (Claude, Hermes, Cursor...): `https://learner.internal/mcp`, with the tools `recall`, `skill_view`,
162
+ `remember`, `record_episode`, `feedback` and `ask`.
163
+
164
+ **Anything else** (LangGraph, CrewAI, OpenAI Agents SDK...):
165
+ ```python
166
+ async with learner.turn(task, user_id="u1") as t:
167
+ out = await run_my_agent(system=BASE + t.instructions, task=task)
168
+ t.add_message("assistant", out)
169
+ t.verify(passed=tests_ok, details=test_log)
170
+ ```
171
+
172
+ **Bring existing skills**: `POST /v1/skills/import` with any SKILL.md (Anthropic, Hermes, agentskills.io). Bulk-import
173
+ history with `POST /v1/episodes:batch`, then `POST /v1/agents/{id}/replay` to warm-start learning offline (ACE's
174
+ offline warm-up lifted its online score from 56.1 to 59.5).
175
+
176
+ ## API
177
+
178
+ | Area | Endpoints |
179
+ |---|---|
180
+ | Loop | `POST /v1/recall`, `POST /v1/episodes`, `POST /v1/episodes:batch`, `POST /v1/feedback`, `POST /v1/traces` (OTLP), `POST /v1/ask` |
181
+ | Skills | `GET /v1/skills`, `GET /v1/skills/{ref}`, `GET …/SKILL.md`, `GET …/versions`, `POST /v1/skills`, `POST /v1/skills/import`, `POST …/rollback`, `POST …/pin`, `POST …/evolve` |
182
+ | Memory | `GET|POST /v1/memories` (`as_of`, `include_history`), `POST …/approve`, `DELETE /v1/memories/{id}`, `GET /v1/profiles/{agent}/{user}` |
183
+ | Governance | `GET /v1/changesets`, `POST /v1/changesets/{id}/review` (`skip_canary`), `POST /v1/agents/{id}/reflect` / `curate` / `replay`, `GET /v1/agents/{id}/insights`, `GET /v1/agents/{id}/export` (JSONL for RL / fine-tuning) |
184
+ | Admin | `POST|DELETE /v1/admin/api-keys`, `GET /v1/admin/audit`, `GET /v1/admin/usage`, `DELETE /v1/admin/users/{id}` |
185
+ | Ops | `/healthz`, `/readyz`, `/metrics`, `/mcp`, `/docs` |
186
+
187
+ ## Enterprise controls
188
+
189
+ - **Identity:** tenant API keys (hashed, revocable) or OIDC (Entra ID, Okta, Auth0, Keycloak). Scopes are `learn`, `review` and `admin`.
190
+ - **Isolation:** every query is tenant-scoped. Knowledge is scoped per agent, with tenant-shared skills under `agent_id="*"`.
191
+ - **Safety:**
192
+ - PII and secrets are redacted before storage.
193
+ - Every changeset is scanned for secrets, prompt injection and oversize content. Flagged changes never auto-apply.
194
+ - Risk tiers: additive = low, edits = medium, removals and routing changes = high (always human).
195
+ - **Change control:**
196
+ - Immutable version snapshots and optimistic concurrency (stale changesets fail instead of clobbering).
197
+ - Canary before full rollout, and one-call rollback.
198
+ - The rejected-change history is kept and learned from.
199
+ - **Privacy:**
200
+ - Right to erasure.
201
+ - Episode retention (`myelinate purge`).
202
+ - Hard memory delete for data-subject requests. Learning itself never hard-deletes.
203
+ - **Cost:** a per-tenant daily token budget. Over-budget jobs are deferred, not failed. Usage is broken down by purpose for chargeback.
204
+ - **Reliability:**
205
+ - A durable job queue with leases, heartbeats, retries and debounce, safe across replicas. Only one job per agent
206
+ reflects at a time.
207
+ - Atomic SQL counter updates, so concurrent runs never lose credit.
208
+ - Idempotency keys (set by the SDKs and derived from the OTel trace id), so retried uploads never double count.
209
+ - Adapters fail open, so a gateway outage never breaks the agent.
210
+ - Canaries that can't reach a verdict expire and keep the incumbent. Queued changes are re-evaluated, never
211
+ silently rebased.
212
+ - **Observability:** Prometheus metrics, including learning-cost and canary-verdict counters. JSON logs carry request and tenant IDs, and OTel tracing is available.
213
+
214
+ ## Layout
215
+
216
+ ```
217
+ src/myelinate/
218
+ engine.py facade: recall / record / credit / feedback / ask / insights / export
219
+ learning.py outcome signal, reflector, evidence gating, curator
220
+ evolution.py GEPA-style evolution with gates
221
+ governance.py changesets, policy, canary experiments, apply, versions, rollback
222
+ memory.py reconcile, bi-temporal store, profile cards
223
+ maintenance.py dedup, lifecycle, nomination, profile refresh
224
+ skills.py delta ops, simulation, diff, SKILL.md render/parse, lint
225
+ experiments.py Beta posteriors, Thompson sampling, lift
226
+ retrieval.py BM25 + dense RRF + MMR embeddings.py optional /v1/embeddings client
227
+ otel.py OTLP → episodes prompts.py role prompts + strict schemas
228
+ core.py metered LLM, budgets, jobs, audit worker.py durable job worker
229
+ gateway/ FastAPI app, auth/RBAC, MCP server adapters/ maf.py, generic.py
230
+ adapters/openclaw TypeScript plugin + reusable TS client
231
+ tests/ 60 tests: loop, gating, tagging, canary, GEPA, memory, dedup, lift, OTel, import, auth, MCP, budget,
232
+ concurrency, idempotency, SDK request shape, regressions
233
+ ```
234
+
235
+ ## Verification status
236
+
237
+ | Check | Result |
238
+ |---|---|
239
+ | Test suite (60 tests) | Passes on SQLite and on PostgreSQL 17 (`MYELINATE_TEST_DATABASE_URL=postgresql+asyncpg://… uv run pytest`), with 5 repeated runs and no flakes |
240
+ | Microsoft Agent Framework adapter | Runs inside a real `agent_framework` 1.22 `Agent` (test) |
241
+ | OpenClaw plugin | Type-checks against the real `openclaw@2026.10.4` SDK. Installs, enables, passes `plugins doctor`, and its hooks and tools register in the real runtime (`inspect --runtime`). **Real agent turns with `anthropic/claude-opus-5-5` close the loop:** (1) the agent followed an injected skill exactly; (2) a user correction given in chat reached the gateway through `rate_last_turn`; (3) Claude reflected and proposed a rule update, which policy held for review; (4) after approval, a brand-new session produced the corrected format |
242
+ | Docker | `docker build` succeeds (415 MB, non-root). `docker compose` (gateway, 2 workers, Postgres) reaches healthy on every service. A failed production migration recorded via the API was learned by a worker replica with real Claude into a correct `postgres-schema-migration` skill stored in Postgres |
243
+ | Claude request path | Real Anthropic SDK (1.15) with a mocked transport: request shape, structured output, fallbacks, usage metering, refusal / max_tokens / 429 / 400 handling. Every schema is checked to be strict |
244
+ | **Live Claude (`claude-opus-5-5`)** | Full pipeline against the real API: outcome judging, reflection, curation (a skill with 3 well-formed rules from one failed deploy), memory reconciliation, learning from a user correction, GEPA evolution (one run accepted at judge 0.46 → 0.80, one rejected for gaining too little), dedup merge, profile card, ask. About $0.44 upper bound for the whole run (31 calls) |
245
+ | Production mode | The built package boots with `MYELINATE_ENV=prod` on PostgreSQL. Verified: auth, scopes, recall, idempotent record, input limits, MCP tool calls, OTLP ingestion, audit, metrics |
246
+ | Static analysis | ruff clean. Pyright reports only known false positives (FastAPI `Annotated` dependencies, SQLAlchemy `rowcount`) |
247
+
248
+ **Not covered here:** load and performance testing, Kubernetes manifests (only Compose ships), and Entra ID / Okta SSO
249
+ against a real identity provider (JWT validation is implemented, but was not tested against one).
250
+
251
+ ## Honest limits
252
+
253
+ - **Learning quality is bounded by signal quality.** Wire `verify_fn` / `t.verify()` / feedback to real checks where
254
+ you can. Without them the system stays conservative (memories only).
255
+ - **The LLM judge used in evolution is a proxy.** That is why changed proven skills are canaried on live traffic. Canaries
256
+ need traffic: with few runs per skill, keep `MYELINATE_AUTO_APPROVE_MEDIUM_RISK=false` and review.
257
+ - **Migrations.** Tables are created at startup. Add Alembic before your first production schema change.
258
+ - **Scale.** Lexical retrieval over a few thousand skills per agent is fine. Beyond that, configure embeddings and move them
259
+ to pgvector. The rate limiter is per process; put a shared limiter in front of multiple replicas.
260
+ - **OTLP** is accepted over HTTP (protobuf or JSON, gzip or not). gRPC needs a Collector in front.
261
+ - **The OpenClaw plugin** targets `openclaw@2026.10.4` (Node ≥24.16 <25 or ≥26.1). Re-run `npx tsc` against newer
262
+ SDK versions when upgrading.
263
+
264
+ ## Contributing and security
265
+
266
+ Issues and pull requests are welcome. CI runs the test suite on SQLite and PostgreSQL, type-checks the OpenClaw plugin
267
+ and builds the Docker image. Please report vulnerabilities privately; see [SECURITY.md](SECURITY.md).
268
+
269
+ ## License
270
+
271
+ [MIT](LICENSE)