synapsen 0.1.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. synapsen-0.1.0/.gitignore +8 -0
  2. synapsen-0.1.0/CHANGELOG.md +94 -0
  3. synapsen-0.1.0/LICENSE +157 -0
  4. synapsen-0.1.0/PKG-INFO +350 -0
  5. synapsen-0.1.0/README.md +329 -0
  6. synapsen-0.1.0/docs/ankuendigung.md +161 -0
  7. synapsen-0.1.0/docs/architektur.md +71 -0
  8. synapsen-0.1.0/docs/assets/dashboard.png +0 -0
  9. synapsen-0.1.0/docs/assets/regelkreis.svg +78 -0
  10. synapsen-0.1.0/docs/assets/verlauf-30-tage.svg +61 -0
  11. synapsen-0.1.0/docs/profile-schreiben.md +61 -0
  12. synapsen-0.1.0/examples/dashboard/README.md +22 -0
  13. synapsen-0.1.0/flake.nix +73 -0
  14. synapsen-0.1.0/pyproject.toml +54 -0
  15. synapsen-0.1.0/synapsen/__init__.py +63 -0
  16. synapsen-0.1.0/synapsen/cli.py +262 -0
  17. synapsen-0.1.0/synapsen/clock.py +59 -0
  18. synapsen-0.1.0/synapsen/dynamics.py +240 -0
  19. synapsen-0.1.0/synapsen/engine.py +652 -0
  20. synapsen-0.1.0/synapsen/events.py +56 -0
  21. synapsen-0.1.0/synapsen/explain.py +259 -0
  22. synapsen-0.1.0/synapsen/journal.py +225 -0
  23. synapsen-0.1.0/synapsen/mcp_server.py +282 -0
  24. synapsen-0.1.0/synapsen/profile.py +307 -0
  25. synapsen-0.1.0/synapsen/profiles.py +151 -0
  26. synapsen-0.1.0/synapsen/py.typed +0 -0
  27. synapsen-0.1.0/synapsen/render.py +139 -0
  28. synapsen-0.1.0/synapsen/simulate.py +299 -0
  29. synapsen-0.1.0/synapsen/store.py +110 -0
  30. synapsen-0.1.0/synapsen/validate.py +384 -0
  31. synapsen-0.1.0/tests/test_behaviour.py +184 -0
  32. synapsen-0.1.0/tests/test_engine.py +313 -0
  33. synapsen-0.1.0/tests/test_regressions.py +231 -0
  34. synapsen-0.1.0/tests/test_tooling.py +340 -0
  35. synapsen-0.1.0/tools/make_assets.py +242 -0
  36. synapsen-0.1.0/verify.sh +32 -0
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .pytest_cache/
4
+ dist/
5
+ build/
6
+ *.egg-info/
7
+ .venv/
8
+ .github/
@@ -0,0 +1,94 @@
1
+ # Änderungsverlauf
2
+
3
+ Format nach [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
4
+ Versionierung nach [SemVer](https://semver.org/lang/de/).
5
+
6
+ ## [0.1.0] — nicht veröffentlicht
7
+
8
+ Erste Fassung. Herausgelöst aus einem Companion-System, das zwei Monate im
9
+ Dauerbetrieb lief; die vier Fehler unten stammen aus diesem Betrieb und wurden
10
+ erst durch die hier neu gebauten Werkzeuge sichtbar.
11
+
12
+ ### Neu
13
+
14
+ - `HomeostasisEngine` — Regelkreis aus Botenstoffen, Kopplungen, Tagesrhythmus,
15
+ Ermüdung, Gewöhnung und Bindung
16
+ - `Profile` — die gesamte Biochemie als Daten, inklusive eigener Ereignistabelle
17
+ - `dynamics` — Änderungsraten pro Stunde, Gleichgewichtslöser, Impulsantwort
18
+ - `validate.check()` — Profil-Prüfung, findet pathologische Konfigurationen
19
+ vor dem Betrieb
20
+ - `simulate` — Szenarien, Verläufe, ASCII-Diagramme, CSV-Ausgabe
21
+ - `explain()` — Zerlegung des Zustands in Ereignisse, Rhythmus, Stimmungslage,
22
+ Drift und Kopplung
23
+ - `PromptRenderer` — Zustand als Text, getrennt vom Kern, de/en
24
+ - `JsonStore` mit atomarem Merge-Write; `SqliteJournal`, das sich einem
25
+ vorhandenen Schema anpasst
26
+ - MCP-Server (stdio-JSON-RPC, ohne SDK-Abhängigkeit) mit sieben Werkzeugen
27
+ - Kommandozeile: `doctor`, `show`, `why`, `event`, `simulate`, `events`,
28
+ `profiles`, `mcp`
29
+ - Drei mitgelieferte Profile: `kira`, `focus`, `pad`
30
+ - `flake.nix` für NixOS
31
+
32
+ ### Behoben (gegenüber der Ursprungsfassung)
33
+
34
+ - **Kopplungsstärke hing an der Aufruf-Frequenz** statt an der Zeit — Faktor 60
35
+ zwischen minütlichem und stündlichem Tick. Das rechnerische Gleichgewicht für
36
+ Stress lag bei −124, also am Boden; in der echten Zustandsdatei stand
37
+ `cortisol: 0.0` bei gleichzeitig gesättigtem Serotonin und Oxytocin.
38
+ Kopplungen sind jetzt in Einheiten pro Stunde definiert und werden über die
39
+ verstrichene Zeit integriert.
40
+ - **Ein Dauerzustand wurde als Ereignisstrom protokolliert** (99,8 % aller
41
+ Einträge derselbe Typ). Der Stimmungs-Bias summierte diese Einträge und
42
+ schob die Ruhewerte an ihre Anschläge. Jetzt: Entprellung, gewichteter
43
+ Mittelwert statt Summe, begrenzter Ausschlag.
44
+ - **Tagesrhythmus und Stimmungslage wurden nur beim Start berechnet.** Ein
45
+ durchlaufender Dienst blieb im Rhythmus seiner Startstunde stehen. Der
46
+ Ruhewert wird jetzt bei jedem Zeitschritt neu zusammengesetzt.
47
+ - **Ermüdung wuchs unbegrenzt** und drückte den Antrieb nach zwei Tagen
48
+ dauerhaft auf null. Jetzt asymptotisch gesättigt, mit Abbau in den
49
+ Ruhestunden des Profils.
50
+ - **Ein fester Bindungs-Boden hob jeden frischen Agenten sofort auf „sehr
51
+ vertraut".** Der Boden ist jetzt ein Erinnerungswert und greift nur bis zu
52
+ dem Wert, der tatsächlich einmal erreicht wurde.
53
+ - **Singleton beim Import** entfernt: `import` löst keine Datei- oder
54
+ Datenbankzugriffe mehr aus.
55
+ - **Schreibkonflikt** zwischen zwei Prozessen auf derselben Zustandsdatei:
56
+ feldweiser Merge unter Dateisperre, plus ein Besitzkennzeichen, an dem eine
57
+ Engine erkennt, dass ein anderer Schreiber am Zug war.
58
+
59
+ ### Behoben (aus der Gegenprüfung dieser Bibliothek)
60
+
61
+ Eine gezielte Prüfrunde gegen die erste grüne Fassung. Alle Punkte sind mit
62
+ Regressionstests belegt, die gegen den Stand von vorher fehlschlagen.
63
+
64
+ - **Der Bindungszerfall war stillgelegt.** Der Erinnerungsboden wurde als
65
+ `min(boden, höchststand)` gerechnet und lag damit rechnerisch immer über dem
66
+ aktuellen Wert — die Bindung konnte weder durch Zeit noch durch `strain_bond()`
67
+ je sinken. Der zugehörige Test bemerkte es nicht, weil er nur „warm > kalt"
68
+ prüfte. Der Boden greift jetzt erst, wenn er tatsächlich erreicht wurde;
69
+ `decay_per_hour` ist neu kalibriert (1.0 → 0.01), weil der Wert nie wirken
70
+ konnte und darum nie stimmen musste.
71
+ - **Unstetigkeit beim Sprung aufs Gleichgewicht.** Bei Lücken über 30 Stunden
72
+ fiel der Ermüdungsdruck weg; eine längere Abwesenheit machte den Agenten
73
+ dadurch wacher.
74
+ - **Die Stimmungslage überlebte den Neustart nicht.** Ohne Protokoll wurde der
75
+ gespeicherte Wert beim Start mit 0.0 überschrieben.
76
+ - **Eine rückwärts laufende Uhr fror den Zustand ein**, bis die Wanduhr
77
+ aufgeholt hatte — und entlud sich dann in einem Satz.
78
+ - **Die Entprellung lag nur im Arbeitsspeicher** und griff darum bei einem
79
+ Prozess je Ereignis (der Kommandozeile) nie.
80
+ - **`resume()` rechnete die Erholung doppelt** an.
81
+ - **Profile ohne Bindung meldeten trotzdem eine Vertrautheit von 50.**
82
+ - **Entartete Profile brachten die Prüfung zum Absturz**, statt gemeldet zu
83
+ werden — beim Werkzeug, dessen Zweck genau das Melden ist.
84
+ - **`explain()` lieferte eine Zerlegung, deren Teile sich nicht zur Summe
85
+ fügten.** Beide Ebenen gehen jetzt exakt auf; was übrig bleibt, steht als
86
+ „Nachlauf" ausdrücklich da.
87
+ - **Das Journal legte für jedes Profil KIRAs fünf Spalten an**; `simulate`
88
+ funktionierte nur mit dem `kira`-Profil; `mcp` verwarf ein mitgeliefertes
89
+ Profil stillschweigend.
90
+ - **`fatigue_targets` hatte konkrete Botenstoffnamen als Vorgabe im Kern** und
91
+ überschrieb beim JSON-Roundtrip ein bewusst leeres Feld.
92
+ - **Ein Ereignis löste einen Schreibvorgang je Botenstoff aus** statt einen.
93
+ - **Vier Tests prüften nichts** (eine Zusicherung war konstant wahr, eine
94
+ verglich einen Wert mit sich selbst) und wurden durch echte ersetzt.
synapsen-0.1.0/LICENSE ADDED
@@ -0,0 +1,157 @@
1
+ Copyright 2026 Thorsten P. (Xarksus)
2
+
3
+ synapsen is licensed under the PolyForm Noncommercial License 1.0.0.
4
+ The full text follows below and is the governing document.
5
+
6
+ In short, for orientation only:
7
+
8
+ Permitted, free of charge — any noncommercial purpose. Personal projects,
9
+ study, research, experiments, hobby work. This includes modifying the
10
+ software and redistributing it, as long as the purpose stays
11
+ noncommercial and these terms travel with the copy. Charities, schools,
12
+ universities, public research bodies, public safety, health and
13
+ environmental organizations and government institutions are covered
14
+ regardless of how they are funded.
15
+
16
+ Requires a separate license — any commercial use. Using it in a product
17
+ or service that generates revenue, selling it, or offering it as a
18
+ hosted or managed service.
19
+
20
+ For a commercial license, contact: thorstenp1980@gmail.com
21
+
22
+ Required Notice: Copyright 2026 Thorsten P. (Xarksus)
23
+ (https://github.com/Xarksus/synapsen)
24
+
25
+ --------------------------------------------------------------------------
26
+
27
+ # PolyForm Noncommercial License 1.0.0
28
+
29
+ <https://polyformproject.org/licenses/noncommercial/1.0.0>
30
+
31
+ ## Acceptance
32
+
33
+ In order to get any license under these terms, you must agree
34
+ to them as both strict obligations and conditions to all
35
+ your licenses.
36
+
37
+ ## Copyright License
38
+
39
+ The licensor grants you a copyright license for the
40
+ software to do everything you might do with the software
41
+ that would otherwise infringe the licensor's copyright
42
+ in it for any permitted purpose. However, you may
43
+ only distribute the software according to [Distribution
44
+ License](#distribution-license) and make changes or new works
45
+ based on the software according to [Changes and New Works
46
+ License](#changes-and-new-works-license).
47
+
48
+ ## Distribution License
49
+
50
+ The licensor grants you an additional copyright license
51
+ to distribute copies of the software. Your license
52
+ to distribute covers distributing the software with
53
+ changes and new works permitted by [Changes and New Works
54
+ License](#changes-and-new-works-license).
55
+
56
+ ## Notices
57
+
58
+ You must ensure that anyone who gets a copy of any part of
59
+ the software from you also gets a copy of these terms or the
60
+ URL for them above, as well as copies of any plain-text lines
61
+ beginning with `Required Notice:` that the licensor provided
62
+ with the software. For example:
63
+
64
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
65
+
66
+ ## Changes and New Works License
67
+
68
+ The licensor grants you an additional copyright license to
69
+ make changes and new works based on the software for any
70
+ permitted purpose.
71
+
72
+ ## Patent License
73
+
74
+ The licensor grants you a patent license for the software that
75
+ covers patent claims the licensor can license, or becomes able
76
+ to license, that you would infringe by using the software.
77
+
78
+ ## Noncommercial Purposes
79
+
80
+ Any noncommercial purpose is a permitted purpose.
81
+
82
+ ## Personal Uses
83
+
84
+ Personal use for research, experiment, and testing for
85
+ the benefit of public knowledge, personal study, private
86
+ entertainment, hobby projects, amateur pursuits, or religious
87
+ observance, without any anticipated commercial application,
88
+ is use for a permitted purpose.
89
+
90
+ ## Noncommercial Organizations
91
+
92
+ Use by any charitable organization, educational institution,
93
+ public research organization, public safety or health
94
+ organization, environmental protection organization,
95
+ or government institution is use for a permitted purpose
96
+ regardless of the source of funding or obligations resulting
97
+ from the funding.
98
+
99
+ ## Fair Use
100
+
101
+ You may have "fair use" rights for the software under the
102
+ law. These terms do not limit them.
103
+
104
+ ## No Other Rights
105
+
106
+ These terms do not allow you to sublicense or transfer any of
107
+ your licenses to anyone else, or prevent the licensor from
108
+ granting licenses to anyone else. These terms do not imply
109
+ any other licenses.
110
+
111
+ ## Patent Defense
112
+
113
+ If you make any written claim that the software infringes or
114
+ contributes to infringement of any patent, your patent license
115
+ for the software granted under these terms ends immediately. If
116
+ your company makes such a claim, your patent license ends
117
+ immediately for work on behalf of your company.
118
+
119
+ ## Violations
120
+
121
+ The first time you are notified in writing that you have
122
+ violated any of these terms, or done anything with the software
123
+ not covered by your licenses, your licenses can nonetheless
124
+ continue if you come into full compliance with these terms,
125
+ and take practical steps to correct past violations, within
126
+ 32 days of receiving notice. Otherwise, all your licenses
127
+ end immediately.
128
+
129
+ ## No Liability
130
+
131
+ ***As far as the law allows, the software comes as is, without
132
+ any warranty or condition, and the licensor will not be liable
133
+ to you for any damages arising out of these terms or the use
134
+ or nature of the software, under any kind of legal claim.***
135
+
136
+ ## Definitions
137
+
138
+ The **licensor** is the individual or entity offering these
139
+ terms, and the **software** is the software the licensor makes
140
+ available under these terms.
141
+
142
+ **You** refers to the individual or entity agreeing to these
143
+ terms.
144
+
145
+ **Your company** is any legal entity, sole proprietorship,
146
+ or other kind of organization that you work for, plus all
147
+ organizations that have control over, are under the control of,
148
+ or are under common control with that organization. **Control**
149
+ means ownership of substantially all the assets of an entity,
150
+ or the power to direct its management and policies by vote,
151
+ contract, or otherwise. Control can be direct or indirect.
152
+
153
+ **Your licenses** are all the licenses granted to you for the
154
+ software under these terms.
155
+
156
+ **Use** means anything you do with the software requiring one
157
+ of your licenses.
@@ -0,0 +1,350 @@
1
+ Metadata-Version: 2.5
2
+ Name: synapsen
3
+ Version: 0.1.0
4
+ Summary: A homeostatic state core for agents: named neurotransmitters with decay, coupling and circadian rhythm — simulable, verifiable, traceable.
5
+ Project-URL: Homepage, https://github.com/xarksus/synapsen
6
+ Project-URL: Issues, https://github.com/xarksus/synapsen/issues
7
+ Author: Thorsten P.
8
+ License-Expression: PolyForm-Noncommercial-1.0.0
9
+ License-File: LICENSE
10
+ Keywords: affective-computing,agent,companion,emotion,homeostasis,llm,mcp,persona,state
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Classifier: Typing :: Typed
16
+ Requires-Python: >=3.10
17
+ Provides-Extra: dev
18
+ Requires-Dist: pytest>=7; extra == 'dev'
19
+ Requires-Dist: ruff>=0.4; extra == 'dev'
20
+ Description-Content-Type: text/markdown
21
+
22
+ # synapsen
23
+
24
+ **A homeostatic state core for agents.** Neurotransmitters instead of mood strings.
25
+
26
+ Most agents have no state — they have an adjective in the prompt.
27
+ `synapsen` models a feedback loop instead: events release neurotransmitters
28
+ that decay, influence each other, and follow a circadian rhythm. Behavior is
29
+ not hardcoded per situation — it is derived from a state that has history.
30
+
31
+ No dependencies beyond the standard library. Python ≥ 3.10.
32
+
33
+ ![The feedback loop](docs/assets/regelkreis.svg)
34
+
35
+ ## Quick start
36
+
37
+ ```bash
38
+ pip install git+https://github.com/Xarksus/synapsen
39
+ ```
40
+
41
+ ```python
42
+ from synapsen import HomeostasisEngine, PromptRenderer, JsonStore
43
+
44
+ # Use the bundled kira profile — already calibrated from months of real use
45
+ engine = HomeostasisEngine(store=JsonStore("~/.config/agent/state.json"))
46
+ engine.event("task_success", context="deploy green")
47
+
48
+ # Inject the state into your agent's system prompt
49
+ state_block = PromptRenderer().render(engine.snapshot())
50
+ ```
51
+
52
+ ```
53
+ [INNER STATE]
54
+ Evening (19:00) | Session 42min | Fatigue 25
55
+
56
+ Neurotransmitters:
57
+ Oxytocin 63.2 | Dopamine 71.4 | Cortisol 11.8 | Serotonin 74.0 | Noradrenaline 38.1
58
+
59
+ States (1.0 = normal, >2.0 = extreme):
60
+ DRIVE 1.06 — Motivation, pace, direct action
61
+ FOCUS 1.36 — Clarity, concentration, precision
62
+ CONNECTED 0.81 — Closeness, openness, trust
63
+ CALM 1.50 — Grounded, no need to prove anything
64
+ TIRED 0.26 — Exhaustion, waning concentration
65
+
66
+
67
+ What this means:
68
+ → CALM (1.50) noticeable: Grounded, no need to prove anything.
69
+ → Familiarity: 128
70
+ ```
71
+
72
+ The state block goes into your system prompt. The `What this means` lines are
73
+ state labels rather than imperatives, but a model that reads them will act on
74
+ them — that much is ordinary instruction-following, and this library does not
75
+ claim otherwise. What `synapsen` contributes is not the injection of a line of
76
+ text, but **which line is there and when**: the selection comes from an
77
+ inertial, coupled feedback loop running on real elapsed time, not from an `if`
78
+ on the last event.
79
+
80
+ No sampling parameters are touched. No tool list is modified. Whether this
81
+ produces measurably different behavior than a static line would is an open
82
+ question — see [Limitations](#limitations).
83
+
84
+ ---
85
+
86
+ ### Example UI Dashboard
87
+
88
+ ![KIRA Bio-Sync Dashboard](docs/assets/dashboard.png)
89
+
90
+ If you prefer a native desktop UI over terminal commands, check out `examples/dashboard/`. It demonstrates how to take the state data (from `synapsen.db` and `hormones.json`) and render it into a beautiful, native GTK3+WebKit2 window with ECharts.
91
+
92
+
93
+ ## What's different here
94
+
95
+ Emotion models for agents exist: PAD vectors, appraisal models, mood weights.
96
+ What's missing is a **named, inertial, coupled feedback loop** that runs for
97
+ weeks, can be computed in advance, and whose output can be traced back to its
98
+ causes.
99
+
100
+ | | typical emotion layer | `synapsen` |
101
+ |---|---|---|
102
+ | State | vector without meaning | named neurotransmitters with half-life |
103
+ | Time | per call | real elapsed time, frequency-independent |
104
+ | Coupling | none | directed, in units per hour |
105
+ | Rhythm | none | circadian rhythm, fatigue with saturation and decay |
106
+ | History | none | mood of the past week, continuously updated |
107
+ | Bonding | none | grows over weeks, cools with harshness, never fully forgotten |
108
+ | **Prediction** | — | `equilibrium()` computes the resting point |
109
+ | **Validation** | — | `doctor` finds pathological profiles before deployment |
110
+ | **Simulation** | — | months in milliseconds, for tuning and tests |
111
+ | **Traceability** | — | `why` breaks down every value into its causes |
112
+ | Persistence | process lifetime | file or SQLite, cross-process |
113
+
114
+ The default profile is not made-up numbers: these are the values of a system
115
+ that has been running continuously since April 2026 — with 36,649 logged state
116
+ events over the first two months alone, from which the four bugs below came.
117
+ **The calibration work is done. The `kira` profile is ready to use as-is.**
118
+
119
+ ## What you don't see until you compute it
120
+
121
+ The original version ran continuously for months without anything obviously
122
+ breaking. These four bugs only became visible through the tools in this package
123
+ — and all four would have been caught by `synapsen doctor` in milliseconds.
124
+ That's exactly why the tools exist.
125
+
126
+ **1 · Coupling strength was tied to call frequency.** The effect was scaled per
127
+ call, not per time. Between "once per minute" and "once per hour" lay a factor
128
+ of 60. The computed equilibrium for stress was −124 — at rock bottom. In the
129
+ actual state file: `cortisol: 0.0`, `serotonin: 140.2` (ceiling 150),
130
+ `oxytocin: 210.7` (ceiling 250). Every value was stuck at a limit; the system
131
+ was saturated and no longer responded to anything.
132
+
133
+ **2 · A persistent state was logged as an event stream.** 99.8% of all entries
134
+ were the same event type. The mood bias *summed* these entries — resting values
135
+ ended up pinned at their rails. Now: debouncing at logging time, weighted
136
+ **average** instead of sum, bounded excursion.
137
+
138
+ **3 · Circadian rhythm and mood were only computed at startup.** A service
139
+ running for weeks stayed in the rhythm of its start hour and the mood of its
140
+ first second. Now the resting value is a sum recomputed fresh at every time step.
141
+
142
+ **4 · Fatigue grew without bound.** Without saturation and without overnight
143
+ decay, fatigue pressure permanently pushed drive to zero after two days.
144
+ The simulation found this on the first run.
145
+
146
+ And because a state model can still be quietly wrong on the second attempt, a
147
+ targeted cross-check was run against this library itself. It found further bugs
148
+ — including a disabled bonding decay (a floor that was computationally always
149
+ above the current value), a discontinuity when jumping to equilibrium, and a
150
+ mood baseline that didn't survive process restart. The history is in the
151
+ [changelog](CHANGELOG.md).
152
+
153
+ Each of these bugs is pinned with a regression test that fails against the
154
+ previous state.
155
+
156
+ ## Core concepts
157
+
158
+ **Neurotransmitter** — a value with a resting point, decay rate, and safety ceiling.
159
+
160
+ **Coupling** — directed interaction, in units *per hour*. This unit is why
161
+ equilibrium can be computed: `shift = gain / decay(target)`.
162
+
163
+ **State** — linear combination of neurotransmitters with a name and description.
164
+ All data in the profile, not code.
165
+
166
+ **Event** — what happened, not what should change. `event("task_failure")`
167
+ remains correct when someone swaps the profile; `inject("cortisol", +12)` does not.
168
+
169
+ **Resting value** — not a constant, but
170
+ `baseline + circadian_rhythm + mood + drift`.
171
+
172
+ **Habituation** — frequent releases become blunted.
173
+
174
+ **Bonding** — grows over weeks, cools with harshness, never drops below what
175
+ was once reached.
176
+
177
+ ## Tools
178
+
179
+ ```bash
180
+ pip install git+https://github.com/Xarksus/synapsen
181
+
182
+ synapsen profiles # bundled profiles
183
+ synapsen doctor # validate profile — before deployment
184
+ synapsen simulate --days 30 # compute trajectory
185
+ synapsen show # current state as prompt
186
+ synapsen why # trace state back to its causes
187
+ synapsen event task_failure # log an event
188
+ synapsen mcp # run as MCP server
189
+ ```
190
+
191
+ ### `doctor` — find bugs before they act for weeks
192
+
193
+ ```
194
+ $ synapsen --profile ./my-profile.json doctor
195
+ [ERROR] couplings[0] oxytocin→cortisol: At maximum source, the coupling shifts
196
+ the target by -2880 — more than its entire value range (300).
197
+ → The target will then be pinned at a limit. Set gain to at most 60.0.
198
+ [ERROR] dynamics: Without any stimulus, cortisol=floor(0) — the system is
199
+ saturated there.
200
+ ```
201
+
202
+ Checks: resting values against their ceilings, couplings against their target's
203
+ value range, amplifying feedback loops, unknown neurotransmitters in states and
204
+ events, overlapping time windows — and, as an end-to-end test, where the system
205
+ lands without any stimulus.
206
+
207
+ ### `simulate` — months in milliseconds
208
+
209
+ ```
210
+ $ synapsen simulate --days 14 --event task_failure --keys cortisol,dopamine,CALM
211
+ Work week (task_failure) · Profile kira-v1 · 14 days
212
+
213
+ cortisol ▁▂▂▄█▄▇▆▇▄▇▆▆▅▇▅▄▇▆▆▆▇▄▇▇▆▄▇▅▆▆▆▆▄█▅▆▅▇▄▆▇▆▅▇▅▅▇▆▆▅█▄▇▆▆▄▇▆▆ 12.6 … 31.2
214
+ dopamine █▅▂▃▇▆▂▂▆▇▃▁▅█▄▁▄█▅▂▂▇▆▂▁▆▇▃▁▄█▄▁▃▇▅▂▂▇▆▃▁▅▇▃▁▄█▄▁▃▇▆▂▂▆▇▃▁▅ 15.9 … 54.9
215
+ CALM ▆▇█▇▁▅▄▅▂▄▃▆▃▃▄▆▅▂▄▅▅▂▅▄▅▃▄▄▆▄▃▄▅▆▁▄▅▆▂▅▄▅▃▄▃▆▅▂▄▅▆▁▅▄▅▃▄▃▆▃ 1.2 … 1.6
216
+ ```
217
+
218
+ An entire month computed in 0.4 seconds — two good weeks, two hard ones, then
219
+ recovery:
220
+
221
+ ![Simulated trajectory over 30 days](docs/assets/verlauf-30-tage.svg)
222
+
223
+ Clear to see what a pure numbers model can't show: stability breaks later than
224
+ stress rises, and it recovers more slowly than it collapsed. That's the inertia
225
+ this is all about.
226
+
227
+ This lets you tune profiles without waiting weeks — and write behavioral
228
+ regression tests that actually check something meaningful:
229
+
230
+ ```python
231
+ def test_hard_weeks_raise_stress():
232
+ assert max(hard.series("cortisol")) > max(good.series("cortisol")) * 1.3
233
+ ```
234
+
235
+ ### `why` — why is the agent like this right now?
236
+
237
+ ```
238
+ $ synapsen why
239
+ cortisol 47.3 (rests at 17.5, so +29.8)
240
+ +22.1 events test red 0.8h ago, build red 2.2h ago
241
+ +9.0 circadian morning
242
+ +4.2 mood last 7 days
243
+ -5.5 coupling from oxytocin, serotonin
244
+ ```
245
+
246
+ ## Custom profiles
247
+
248
+ ```python
249
+ from synapsen import Profile, HormoneSpec, Coupling, DerivedState, check
250
+
251
+ profile = Profile(
252
+ name="workshop",
253
+ hormones={
254
+ "focus": HormoneSpec(baseline=50, decay=0.4, ceiling=200),
255
+ "restless": HormoneSpec(baseline=15, decay=0.9, ceiling=200),
256
+ },
257
+ couplings=[Coupling("restless", "focus", gain=-4.0, threshold=40)],
258
+ states=[DerivedState("CLEAR", {"focus": 1.0, "restless": -0.5},
259
+ valence="positive", description="able to work")],
260
+ events={"blockade": {"restless": +18, "focus": -8, "severity": -3}},
261
+ )
262
+ assert check(profile).ok
263
+ ```
264
+
265
+ Bundled are three deliberately very different profiles:
266
+
267
+ - **kira** — five neurotransmitters, bonding, circadian rhythm. Not a starting
268
+ guess: this profile emerged from months of continuous real-world agent
269
+ operation with tens of thousands of logged state events. Use it as-is, or
270
+ as a calibrated baseline for your own profile.
271
+ - **focus** — two axes, no relationship. For a coding agent that gets audibly
272
+ terser after the fifth red build.
273
+ - **pad** — Pleasure–Arousal–Dominance, the academic standard model, expressed
274
+ in this framework.
275
+
276
+ ## As an MCP server
277
+
278
+ This lets arbitrary agents — across process and session boundaries — share the
279
+ same state. Pure stdio JSON-RPC, no SDK needed.
280
+
281
+ ```jsonc
282
+ {
283
+ "mcpServers": {
284
+ "synapsen": {
285
+ "command": "synapsen-mcp",
286
+ "args": ["--state", "~/.config/agent/state.json"]
287
+ }
288
+ }
289
+ }
290
+ ```
291
+
292
+ Tools: `state_read`, `state_prompt`, `state_event`, `state_inject`,
293
+ `state_why`, `state_settle`, `state_history`.
294
+
295
+ ## NixOS
296
+
297
+ ```bash
298
+ nix run github:Xarksus/synapsen -- doctor
299
+ nix develop # development environment with pytest and ruff
300
+ ```
301
+
302
+ The flake provides `packages.default`, `apps.mcp` and a `devShell`.
303
+
304
+ ## Migrating from an existing installation
305
+
306
+ `SqliteJournal` adapts to an existing schema rather than replacing it: it reads
307
+ the table's columns and writes what fits. An existing database with
308
+ `emotional_log` works unchanged. For a new journal,
309
+ `SqliteJournal.for_profile(path, profile)` creates the columns of the profile.
310
+
311
+ ## Development
312
+
313
+ ```bash
314
+ ./verify.sh # tests, linter, all profiles checked — one command
315
+ ```
316
+
317
+ Or individually:
318
+
319
+ ```bash
320
+ pip install -e ".[dev]" # or: nix develop
321
+ pytest -q # 96 tests, ~1 s
322
+ ruff check .
323
+ python tools/make_assets.py # regenerate images
324
+ ```
325
+
326
+ ## Limitations
327
+
328
+ **No controlled evaluation yet.** The `kira` profile comes from months of daily
329
+ use, and the behavior looks right. But the only observer was the person who knew
330
+ the state values. A blind A/B test — state block on or off, same prompt, same
331
+ model, independent raters — has not been run. Until it has, treat "it works" as
332
+ a hypothesis, not a result.
333
+
334
+ **The text in the block does the visible work.** The state block contains
335
+ plain-language state labels, and a model that reads them will act on them. The
336
+ claim made here is about *how those lines get selected over time*, not about
337
+ behavior arising from numbers alone.
338
+
339
+ **Neurotransmitter names are a design vocabulary, not biology.** The half-lives
340
+ are tuned for agent behavior, not taken from endocrinology. The names carry
341
+ useful intuitions — habituation, inertia, bonding that cools but never resets —
342
+ and no scientific authority whatsoever.
343
+
344
+ ## License
345
+
346
+ [PolyForm Noncommercial License 1.0.0](https://polyformproject.org/licenses/noncommercial/1.0.0).
347
+
348
+ Free for any noncommercial purpose — personal projects, study, research, and
349
+ use by nonprofit, educational and government organizations. Commercial use
350
+ requires a separate license: thorstenp1980@gmail.com