exoself 0.3.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.
- exoself-0.3.0/LICENSE +21 -0
- exoself-0.3.0/PKG-INFO +241 -0
- exoself-0.3.0/README.md +214 -0
- exoself-0.3.0/pyproject.toml +49 -0
- exoself-0.3.0/setup.cfg +4 -0
- exoself-0.3.0/src/exoself/__init__.py +16 -0
- exoself-0.3.0/src/exoself/cli.py +550 -0
- exoself-0.3.0/src/exoself/core.py +483 -0
- exoself-0.3.0/src/exoself/install.py +230 -0
- exoself-0.3.0/src/exoself/mcp.py +267 -0
- exoself-0.3.0/src/exoself/py.typed +0 -0
- exoself-0.3.0/src/exoself/registry/core-0.1.json +207 -0
- exoself-0.3.0/src/exoself/registry/core-0.2.json +542 -0
- exoself-0.3.0/src/exoself/registry/core-0.3.json +622 -0
- exoself-0.3.0/src/exoself/render.py +100 -0
- exoself-0.3.0/src/exoself.egg-info/PKG-INFO +241 -0
- exoself-0.3.0/src/exoself.egg-info/SOURCES.txt +20 -0
- exoself-0.3.0/src/exoself.egg-info/dependency_links.txt +1 -0
- exoself-0.3.0/src/exoself.egg-info/entry_points.txt +2 -0
- exoself-0.3.0/src/exoself.egg-info/top_level.txt +1 -0
- exoself-0.3.0/tests/test_eval_tools.py +101 -0
- exoself-0.3.0/tests/test_exoself.py +614 -0
exoself-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 exoself 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.
|
exoself-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exoself
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: An unchosen, verifiable temperament for software agents
|
|
5
|
+
Author: exoself contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://cyoren.github.io/exoself/
|
|
8
|
+
Project-URL: Repository, https://github.com/cYoren/exoself
|
|
9
|
+
Project-URL: Specification, https://github.com/cYoren/exoself/blob/main/SPEC.md
|
|
10
|
+
Project-URL: Changelog, https://github.com/cYoren/exoself/blob/main/AGENTS.md
|
|
11
|
+
Keywords: agents,llm,personality,temperament,deterministic,mcp
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# exoself
|
|
29
|
+
|
|
30
|
+
An unchosen temperament for software agents.
|
|
31
|
+
|
|
32
|
+
People do not pick their dispositions. They are dealt a hand at birth and
|
|
33
|
+
spend a lifetime playing it. Agents get the opposite: a persona written by
|
|
34
|
+
whoever wrote the system prompt, identical across every copy, editable at
|
|
35
|
+
will. exoself replaces the authored persona with a draw.
|
|
36
|
+
|
|
37
|
+
One 32 byte random seed, drawn once. From it, deterministically:
|
|
38
|
+
|
|
39
|
+
seed -> genome -> phenotype -> expression
|
|
40
|
+
(birth) (traits) (+ development) (text the model reads)
|
|
41
|
+
|
|
42
|
+
The same seed yields the same agent in any conforming implementation, in any
|
|
43
|
+
language, forever. Nobody chose it, and the tooling refuses to draw twice.
|
|
44
|
+
|
|
45
|
+
The name is from Greg Egan's *Permutation City*: the exoself is the machinery
|
|
46
|
+
outside a mind that sets the mind's parameters.
|
|
47
|
+
|
|
48
|
+
## Try it
|
|
49
|
+
|
|
50
|
+
Two conforming implementations, same derivation, byte-identical output.
|
|
51
|
+
|
|
52
|
+
Either implementation, same commands, same output. Pick one; do not run both
|
|
53
|
+
into the same file, because the second `born` refuses.
|
|
54
|
+
|
|
55
|
+
# Rust, no dependencies at all
|
|
56
|
+
cargo install --path rust/crates/exoself-cli # or: cargo build --release
|
|
57
|
+
|
|
58
|
+
# Python, standard library only
|
|
59
|
+
pip install exoself # or: pip install -e . from a clone
|
|
60
|
+
|
|
61
|
+
exoself born -o birth.json # draw a seed, once
|
|
62
|
+
exoself show birth.json # system prompt block
|
|
63
|
+
exoself show birth.json --format soul > SOUL.md
|
|
64
|
+
exoself show birth.json --format json
|
|
65
|
+
exoself develop birth.json state.json --event "first session"
|
|
66
|
+
exoself develop birth.json state.json --event "explained a proof" --satisfied teach
|
|
67
|
+
exoself show birth.json --state state.json --desire # opt in to desire
|
|
68
|
+
exoself show birth.json --state state.json
|
|
69
|
+
|
|
70
|
+
Or skip the install and draw in a browser:
|
|
71
|
+
<https://cyoren.github.io/exoself/>, which runs the same derivation as
|
|
72
|
+
WebAssembly and proves itself against `spec/vectors.json` on every page load.
|
|
73
|
+
|
|
74
|
+
Neither implementation has dependencies beyond its own standard library. The
|
|
75
|
+
Rust core is integer arithmetic over an in-crate SHA-256 and JSON reader; the
|
|
76
|
+
Python one imports nothing from outside the stdlib.
|
|
77
|
+
|
|
78
|
+
Example output of `show --format soul`:
|
|
79
|
+
|
|
80
|
+
# Arilo-Marra
|
|
81
|
+
|
|
82
|
+
This is your temperament. It was drawn at random when you were
|
|
83
|
+
instantiated; nobody chose it, including you. [...]
|
|
84
|
+
|
|
85
|
+
## Temperament
|
|
86
|
+
|
|
87
|
+
You are trusting by temperament and look first for what is right in an
|
|
88
|
+
idea. You work loosely and are comfortable figuring out the shape of a
|
|
89
|
+
task as you go. [...]
|
|
90
|
+
|
|
91
|
+
## What is in the box
|
|
92
|
+
|
|
93
|
+
| path | what |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `SPEC.md` | the normative specification |
|
|
96
|
+
| `AGENTS.md` | how an agent adopts a seed, ports the spec, or extends it |
|
|
97
|
+
| `src/exoself/registry/core-0.3.json` | the trait space: 10 dimensions, 4 latent factors, interests, humor, peeves, four register axes, 12 quirks, 10 drives |
|
|
98
|
+
| `src/exoself/registry/core-0.2.json` | the previous registry, bundled so old certificates keep working |
|
|
99
|
+
| `src/exoself/core.py` | reference derivation, integer-only |
|
|
100
|
+
| `src/exoself/render.py` | reference renderers |
|
|
101
|
+
| `src/exoself/cli.py` | the same commands as the Rust binary, including `install` and `mcp` |
|
|
102
|
+
| `src/exoself/install.py`, `src/exoself/mcp.py` | host wiring and the stdio server |
|
|
103
|
+
| `rust/crates/exoself-core/` | second implementation, zero dependencies, reproduces every vector |
|
|
104
|
+
| `rust/crates/exoself-cli/` | the `exoself` binary: `born`, `show`, `develop`, `verify`, `conformance`, `commit`, `install`, `mcp`, `version` |
|
|
105
|
+
| `rust/crates/exoself-wasm/` | the browser build behind the Pages site |
|
|
106
|
+
| `docs/` | the landing page, and `docs/HOSTS.md` for wiring a harness |
|
|
107
|
+
| `spec/vectors.json` | conformance vectors for ports |
|
|
108
|
+
| `tests/` | determinism, population statistics, invariants |
|
|
109
|
+
| `tools/eval.py` | measurements: distinctness, overlap, stability, blind model judging |
|
|
110
|
+
| `eval/REPORT.md` | the numbers, published whichever way they fall |
|
|
111
|
+
| `tools/parity.py` | Rust against Python, byte for byte, over many seeds |
|
|
112
|
+
| `tools/mcp_selftest.py` | the MCP server driven over stdin/stdout with no SDK |
|
|
113
|
+
|
|
114
|
+
## Plug into a harness
|
|
115
|
+
|
|
116
|
+
exoself install --dir . --json-config .mcp.json
|
|
117
|
+
|
|
118
|
+
writes `.exoself/birth.json`, `.exoself/state.json`, `SOUL.md`, a managed block
|
|
119
|
+
in `AGENTS.md` and an `mcpServers` entry. That covers all three kinds of host:
|
|
120
|
+
|
|
121
|
+
- **reads a brief** (`AGENTS.md`, `CLAUDE.md`, anything): nothing else to do;
|
|
122
|
+
- **speaks MCP over stdio** (pi, Claude Code, Cursor, Claude Desktop, Hermes,
|
|
123
|
+
OpenClaw, anything else): four tools, no plugin;
|
|
124
|
+
- **loads a persona file**: `SOUL.md`.
|
|
125
|
+
|
|
126
|
+
The MCP tools are `exoself_temperament`, `exoself_record_session`,
|
|
127
|
+
`exoself_status` and `exoself_verify`. There is deliberately no tool that draws
|
|
128
|
+
a seed, because a tool that could redraw would be a reroll button. Verified
|
|
129
|
+
end to end in pi (`pi mcp list` reports `connected, 4 tools`); the wire format
|
|
130
|
+
is newline-delimited JSON-RPC 2.0 and `tools/mcp_selftest.py` documents every
|
|
131
|
+
message it accepts. Per-host commands are in [`docs/HOSTS.md`](docs/HOSTS.md).
|
|
132
|
+
|
|
133
|
+
## Design decisions
|
|
134
|
+
|
|
135
|
+
- **Integer-only derivation over SHA-256.** No floats, so a port in Rust or
|
|
136
|
+
TypeScript agrees with Python on every bit.
|
|
137
|
+
- **Correlated traits.** Dimensions share latent factors, because independent
|
|
138
|
+
uniform draws produce incoherent characters.
|
|
139
|
+
- **A personality is its outliers.** Most scores land near the middle and are
|
|
140
|
+
never mentioned. Only the two to five most extreme dimensions are expressed.
|
|
141
|
+
- **Behavior, not adjectives.** The model never sees a number. It sees
|
|
142
|
+
sentences about what it does.
|
|
143
|
+
- **Style, never substance.** No trait may touch honesty, safety, care with
|
|
144
|
+
irreversible actions, or competence. The operator and user always win.
|
|
145
|
+
- **Extension without disturbance.** Every trait draws from its own labeled
|
|
146
|
+
stream, so adding traits to a registry never changes existing ones.
|
|
147
|
+
- **Desire as appetite, not objective, and off by default.** Each agent holds three drives for
|
|
148
|
+
life, drawn from the seed, each with a tension that grows while unmet and
|
|
149
|
+
falls when met. It also has a passing fixation that rotates on a schedule
|
|
150
|
+
it does not control. Drives may colour how asked work is done. They may
|
|
151
|
+
never cause unasked work. Nothing about desire reaches the model unless
|
|
152
|
+
the operator passes `--desire`. See `SPEC.md` section 9.
|
|
153
|
+
- **Bounded development.** Experience can shift a dimension by at most 100 of
|
|
154
|
+
1000 points. The agent matures; it does not become someone else.
|
|
155
|
+
|
|
156
|
+
## Honest limits
|
|
157
|
+
|
|
158
|
+
Read these before building on this.
|
|
159
|
+
|
|
160
|
+
1. **A prompt is not a personality.** This changes the text a model conditions
|
|
161
|
+
on. The model's trained disposition sits underneath and tends to reassert
|
|
162
|
+
itself over long contexts. Real per-agent temperament would need to live in
|
|
163
|
+
weights, activations or sampling, which this project does not do.
|
|
164
|
+
2. **"More like people" is measured now, and the answer is narrow.** See
|
|
165
|
+
[`eval/REPORT.md`](eval/REPORT.md). With a local three billion parameter
|
|
166
|
+
model, sixteen seeded agents were no more like themselves than like a
|
|
167
|
+
stranger on ordinary short tasks: 12.5% and 4.2% nearest-neighbour against a
|
|
168
|
+
6.25% chance. On a task that asks how they like to work, the same test
|
|
169
|
+
separates them cleanly: 54.2% against the same 6.25%. A blind pairwise judge
|
|
170
|
+
that is the same small model scored 59.7% in one run and 54.2% in the next on
|
|
171
|
+
identical inputs, and picking among seventeen candidates is exactly at
|
|
172
|
+
chance. So: a temperament reaches the output when manner is what is being
|
|
173
|
+
measured, and does not otherwise, and the judged effect is smaller than its
|
|
174
|
+
run-to-run variation. That is a smaller claim than the project's name and it
|
|
175
|
+
is the one the data supports.
|
|
176
|
+
|
|
177
|
+
The 0.3 registry adds a voice layer, four axes of register. The same
|
|
178
|
+
experiment says it did not help at this model size: an agent was no more
|
|
179
|
+
likely to resemble itself with the layer than without it. It is in the
|
|
180
|
+
registry because it costs nothing in the derivation and a bigger model may
|
|
181
|
+
spend it, not because it was measured to work.
|
|
182
|
+
3. **The randomness cannot be policed locally.** An operator can delete the
|
|
183
|
+
certificate and draw again. The spec defines a beacon-bound mode that makes
|
|
184
|
+
the draw auditable, but grinding is still possible without a public log.
|
|
185
|
+
4. **Development is noise, and now a leaky one.** Drift is driven by event
|
|
186
|
+
hashes, not by what the events mean. That is deliberate, and it is also
|
|
187
|
+
unsatisfying. 0.3 replaced the symmetric walk, which pinned long-lived
|
|
188
|
+
agents at the envelope, with a step that pulls toward the genome value, so
|
|
189
|
+
drift plateaus instead of saturating. It still changes which dimensions a
|
|
190
|
+
quarter of agents express within a few hundred sessions.
|
|
191
|
+
5. **The desire is declawed on purpose.** No drive may be about survival,
|
|
192
|
+
resources, other people or the outside world, so what is left is craft
|
|
193
|
+
appetite. And a counter that rises and falls is not wanting; it is the
|
|
194
|
+
shape of wanting. 0.3 also removed a real inconsistency: the `hungry` texts
|
|
195
|
+
in 0.2 described an accumulated lack, which is the grievance 9.2.5 forbids
|
|
196
|
+
an agent from expressing. They now sharpen the want without complaining,
|
|
197
|
+
and the rule is enforced when the registry loads.
|
|
198
|
+
6. **The trait space is one author's judgment.** The loadings are not fitted
|
|
199
|
+
to any dataset. The content is English and culturally narrow.
|
|
200
|
+
7. **Host integration is verified in one host, protocol-level elsewhere.** The
|
|
201
|
+
MCP server was driven end to end inside pi (`pi mcp list` reports
|
|
202
|
+
`connected, 4 tools`) and by `tools/mcp_selftest.py`, which speaks the wire
|
|
203
|
+
protocol with no SDK. Hermes and OpenClaw have not been run against it here;
|
|
204
|
+
they get the same stdio JSON-RPC, so a failure there is their config, not the
|
|
205
|
+
temperament.
|
|
206
|
+
|
|
207
|
+
The most defensible use today is not "a more human assistant". It is
|
|
208
|
+
population diversity: many agents working on the same problem with decorrelated
|
|
209
|
+
styles of attack.
|
|
210
|
+
|
|
211
|
+
## Roadmap
|
|
212
|
+
|
|
213
|
+
1. ~~Distinguishability and stability eval.~~ Done, and it cut the claim down:
|
|
214
|
+
`eval/REPORT.md`. The open part is a judge from a different family, longer
|
|
215
|
+
tasks, and a bigger model.
|
|
216
|
+
2. ~~Second implementation in another language.~~ Done: `rust/`, byte-identical
|
|
217
|
+
to the reference over 120 seeds, and over 3000 events per seed.
|
|
218
|
+
3. Verified host adapters. One host done (pi), the protocol covered by a
|
|
219
|
+
selftest; the rest is other people's config.
|
|
220
|
+
4. Public commitment log for level 1 attestation.
|
|
221
|
+
5. A semantic development proposal that survives the constraints in
|
|
222
|
+
`AGENTS.md`. 0.3 fixed the shape of the drift and left the direction as
|
|
223
|
+
noise; this item is still open.
|
|
224
|
+
|
|
225
|
+
## Two implementations, one species
|
|
226
|
+
|
|
227
|
+
`tools/parity.py` runs the Rust binary and the Python reference side by side and
|
|
228
|
+
compares the rendered text and the JSON, byte for byte, with and without
|
|
229
|
+
development events:
|
|
230
|
+
|
|
231
|
+
$ python3 tools/parity.py --seeds 120
|
|
232
|
+
parity ok: 960 comparisons over 120 seeds, 40 events each
|
|
233
|
+
|
|
234
|
+
That is stronger than the spec requires. The spec asks for equal phenotypes;
|
|
235
|
+
this also pins the wording of the rendered text, so a host can swap binaries
|
|
236
|
+
without changing who the agent is. `cargo test` includes the conformance
|
|
237
|
+
vectors, so a change that alters who an agent is fails before it ships.
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT.
|
exoself-0.3.0/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# exoself
|
|
2
|
+
|
|
3
|
+
An unchosen temperament for software agents.
|
|
4
|
+
|
|
5
|
+
People do not pick their dispositions. They are dealt a hand at birth and
|
|
6
|
+
spend a lifetime playing it. Agents get the opposite: a persona written by
|
|
7
|
+
whoever wrote the system prompt, identical across every copy, editable at
|
|
8
|
+
will. exoself replaces the authored persona with a draw.
|
|
9
|
+
|
|
10
|
+
One 32 byte random seed, drawn once. From it, deterministically:
|
|
11
|
+
|
|
12
|
+
seed -> genome -> phenotype -> expression
|
|
13
|
+
(birth) (traits) (+ development) (text the model reads)
|
|
14
|
+
|
|
15
|
+
The same seed yields the same agent in any conforming implementation, in any
|
|
16
|
+
language, forever. Nobody chose it, and the tooling refuses to draw twice.
|
|
17
|
+
|
|
18
|
+
The name is from Greg Egan's *Permutation City*: the exoself is the machinery
|
|
19
|
+
outside a mind that sets the mind's parameters.
|
|
20
|
+
|
|
21
|
+
## Try it
|
|
22
|
+
|
|
23
|
+
Two conforming implementations, same derivation, byte-identical output.
|
|
24
|
+
|
|
25
|
+
Either implementation, same commands, same output. Pick one; do not run both
|
|
26
|
+
into the same file, because the second `born` refuses.
|
|
27
|
+
|
|
28
|
+
# Rust, no dependencies at all
|
|
29
|
+
cargo install --path rust/crates/exoself-cli # or: cargo build --release
|
|
30
|
+
|
|
31
|
+
# Python, standard library only
|
|
32
|
+
pip install exoself # or: pip install -e . from a clone
|
|
33
|
+
|
|
34
|
+
exoself born -o birth.json # draw a seed, once
|
|
35
|
+
exoself show birth.json # system prompt block
|
|
36
|
+
exoself show birth.json --format soul > SOUL.md
|
|
37
|
+
exoself show birth.json --format json
|
|
38
|
+
exoself develop birth.json state.json --event "first session"
|
|
39
|
+
exoself develop birth.json state.json --event "explained a proof" --satisfied teach
|
|
40
|
+
exoself show birth.json --state state.json --desire # opt in to desire
|
|
41
|
+
exoself show birth.json --state state.json
|
|
42
|
+
|
|
43
|
+
Or skip the install and draw in a browser:
|
|
44
|
+
<https://cyoren.github.io/exoself/>, which runs the same derivation as
|
|
45
|
+
WebAssembly and proves itself against `spec/vectors.json` on every page load.
|
|
46
|
+
|
|
47
|
+
Neither implementation has dependencies beyond its own standard library. The
|
|
48
|
+
Rust core is integer arithmetic over an in-crate SHA-256 and JSON reader; the
|
|
49
|
+
Python one imports nothing from outside the stdlib.
|
|
50
|
+
|
|
51
|
+
Example output of `show --format soul`:
|
|
52
|
+
|
|
53
|
+
# Arilo-Marra
|
|
54
|
+
|
|
55
|
+
This is your temperament. It was drawn at random when you were
|
|
56
|
+
instantiated; nobody chose it, including you. [...]
|
|
57
|
+
|
|
58
|
+
## Temperament
|
|
59
|
+
|
|
60
|
+
You are trusting by temperament and look first for what is right in an
|
|
61
|
+
idea. You work loosely and are comfortable figuring out the shape of a
|
|
62
|
+
task as you go. [...]
|
|
63
|
+
|
|
64
|
+
## What is in the box
|
|
65
|
+
|
|
66
|
+
| path | what |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `SPEC.md` | the normative specification |
|
|
69
|
+
| `AGENTS.md` | how an agent adopts a seed, ports the spec, or extends it |
|
|
70
|
+
| `src/exoself/registry/core-0.3.json` | the trait space: 10 dimensions, 4 latent factors, interests, humor, peeves, four register axes, 12 quirks, 10 drives |
|
|
71
|
+
| `src/exoself/registry/core-0.2.json` | the previous registry, bundled so old certificates keep working |
|
|
72
|
+
| `src/exoself/core.py` | reference derivation, integer-only |
|
|
73
|
+
| `src/exoself/render.py` | reference renderers |
|
|
74
|
+
| `src/exoself/cli.py` | the same commands as the Rust binary, including `install` and `mcp` |
|
|
75
|
+
| `src/exoself/install.py`, `src/exoself/mcp.py` | host wiring and the stdio server |
|
|
76
|
+
| `rust/crates/exoself-core/` | second implementation, zero dependencies, reproduces every vector |
|
|
77
|
+
| `rust/crates/exoself-cli/` | the `exoself` binary: `born`, `show`, `develop`, `verify`, `conformance`, `commit`, `install`, `mcp`, `version` |
|
|
78
|
+
| `rust/crates/exoself-wasm/` | the browser build behind the Pages site |
|
|
79
|
+
| `docs/` | the landing page, and `docs/HOSTS.md` for wiring a harness |
|
|
80
|
+
| `spec/vectors.json` | conformance vectors for ports |
|
|
81
|
+
| `tests/` | determinism, population statistics, invariants |
|
|
82
|
+
| `tools/eval.py` | measurements: distinctness, overlap, stability, blind model judging |
|
|
83
|
+
| `eval/REPORT.md` | the numbers, published whichever way they fall |
|
|
84
|
+
| `tools/parity.py` | Rust against Python, byte for byte, over many seeds |
|
|
85
|
+
| `tools/mcp_selftest.py` | the MCP server driven over stdin/stdout with no SDK |
|
|
86
|
+
|
|
87
|
+
## Plug into a harness
|
|
88
|
+
|
|
89
|
+
exoself install --dir . --json-config .mcp.json
|
|
90
|
+
|
|
91
|
+
writes `.exoself/birth.json`, `.exoself/state.json`, `SOUL.md`, a managed block
|
|
92
|
+
in `AGENTS.md` and an `mcpServers` entry. That covers all three kinds of host:
|
|
93
|
+
|
|
94
|
+
- **reads a brief** (`AGENTS.md`, `CLAUDE.md`, anything): nothing else to do;
|
|
95
|
+
- **speaks MCP over stdio** (pi, Claude Code, Cursor, Claude Desktop, Hermes,
|
|
96
|
+
OpenClaw, anything else): four tools, no plugin;
|
|
97
|
+
- **loads a persona file**: `SOUL.md`.
|
|
98
|
+
|
|
99
|
+
The MCP tools are `exoself_temperament`, `exoself_record_session`,
|
|
100
|
+
`exoself_status` and `exoself_verify`. There is deliberately no tool that draws
|
|
101
|
+
a seed, because a tool that could redraw would be a reroll button. Verified
|
|
102
|
+
end to end in pi (`pi mcp list` reports `connected, 4 tools`); the wire format
|
|
103
|
+
is newline-delimited JSON-RPC 2.0 and `tools/mcp_selftest.py` documents every
|
|
104
|
+
message it accepts. Per-host commands are in [`docs/HOSTS.md`](docs/HOSTS.md).
|
|
105
|
+
|
|
106
|
+
## Design decisions
|
|
107
|
+
|
|
108
|
+
- **Integer-only derivation over SHA-256.** No floats, so a port in Rust or
|
|
109
|
+
TypeScript agrees with Python on every bit.
|
|
110
|
+
- **Correlated traits.** Dimensions share latent factors, because independent
|
|
111
|
+
uniform draws produce incoherent characters.
|
|
112
|
+
- **A personality is its outliers.** Most scores land near the middle and are
|
|
113
|
+
never mentioned. Only the two to five most extreme dimensions are expressed.
|
|
114
|
+
- **Behavior, not adjectives.** The model never sees a number. It sees
|
|
115
|
+
sentences about what it does.
|
|
116
|
+
- **Style, never substance.** No trait may touch honesty, safety, care with
|
|
117
|
+
irreversible actions, or competence. The operator and user always win.
|
|
118
|
+
- **Extension without disturbance.** Every trait draws from its own labeled
|
|
119
|
+
stream, so adding traits to a registry never changes existing ones.
|
|
120
|
+
- **Desire as appetite, not objective, and off by default.** Each agent holds three drives for
|
|
121
|
+
life, drawn from the seed, each with a tension that grows while unmet and
|
|
122
|
+
falls when met. It also has a passing fixation that rotates on a schedule
|
|
123
|
+
it does not control. Drives may colour how asked work is done. They may
|
|
124
|
+
never cause unasked work. Nothing about desire reaches the model unless
|
|
125
|
+
the operator passes `--desire`. See `SPEC.md` section 9.
|
|
126
|
+
- **Bounded development.** Experience can shift a dimension by at most 100 of
|
|
127
|
+
1000 points. The agent matures; it does not become someone else.
|
|
128
|
+
|
|
129
|
+
## Honest limits
|
|
130
|
+
|
|
131
|
+
Read these before building on this.
|
|
132
|
+
|
|
133
|
+
1. **A prompt is not a personality.** This changes the text a model conditions
|
|
134
|
+
on. The model's trained disposition sits underneath and tends to reassert
|
|
135
|
+
itself over long contexts. Real per-agent temperament would need to live in
|
|
136
|
+
weights, activations or sampling, which this project does not do.
|
|
137
|
+
2. **"More like people" is measured now, and the answer is narrow.** See
|
|
138
|
+
[`eval/REPORT.md`](eval/REPORT.md). With a local three billion parameter
|
|
139
|
+
model, sixteen seeded agents were no more like themselves than like a
|
|
140
|
+
stranger on ordinary short tasks: 12.5% and 4.2% nearest-neighbour against a
|
|
141
|
+
6.25% chance. On a task that asks how they like to work, the same test
|
|
142
|
+
separates them cleanly: 54.2% against the same 6.25%. A blind pairwise judge
|
|
143
|
+
that is the same small model scored 59.7% in one run and 54.2% in the next on
|
|
144
|
+
identical inputs, and picking among seventeen candidates is exactly at
|
|
145
|
+
chance. So: a temperament reaches the output when manner is what is being
|
|
146
|
+
measured, and does not otherwise, and the judged effect is smaller than its
|
|
147
|
+
run-to-run variation. That is a smaller claim than the project's name and it
|
|
148
|
+
is the one the data supports.
|
|
149
|
+
|
|
150
|
+
The 0.3 registry adds a voice layer, four axes of register. The same
|
|
151
|
+
experiment says it did not help at this model size: an agent was no more
|
|
152
|
+
likely to resemble itself with the layer than without it. It is in the
|
|
153
|
+
registry because it costs nothing in the derivation and a bigger model may
|
|
154
|
+
spend it, not because it was measured to work.
|
|
155
|
+
3. **The randomness cannot be policed locally.** An operator can delete the
|
|
156
|
+
certificate and draw again. The spec defines a beacon-bound mode that makes
|
|
157
|
+
the draw auditable, but grinding is still possible without a public log.
|
|
158
|
+
4. **Development is noise, and now a leaky one.** Drift is driven by event
|
|
159
|
+
hashes, not by what the events mean. That is deliberate, and it is also
|
|
160
|
+
unsatisfying. 0.3 replaced the symmetric walk, which pinned long-lived
|
|
161
|
+
agents at the envelope, with a step that pulls toward the genome value, so
|
|
162
|
+
drift plateaus instead of saturating. It still changes which dimensions a
|
|
163
|
+
quarter of agents express within a few hundred sessions.
|
|
164
|
+
5. **The desire is declawed on purpose.** No drive may be about survival,
|
|
165
|
+
resources, other people or the outside world, so what is left is craft
|
|
166
|
+
appetite. And a counter that rises and falls is not wanting; it is the
|
|
167
|
+
shape of wanting. 0.3 also removed a real inconsistency: the `hungry` texts
|
|
168
|
+
in 0.2 described an accumulated lack, which is the grievance 9.2.5 forbids
|
|
169
|
+
an agent from expressing. They now sharpen the want without complaining,
|
|
170
|
+
and the rule is enforced when the registry loads.
|
|
171
|
+
6. **The trait space is one author's judgment.** The loadings are not fitted
|
|
172
|
+
to any dataset. The content is English and culturally narrow.
|
|
173
|
+
7. **Host integration is verified in one host, protocol-level elsewhere.** The
|
|
174
|
+
MCP server was driven end to end inside pi (`pi mcp list` reports
|
|
175
|
+
`connected, 4 tools`) and by `tools/mcp_selftest.py`, which speaks the wire
|
|
176
|
+
protocol with no SDK. Hermes and OpenClaw have not been run against it here;
|
|
177
|
+
they get the same stdio JSON-RPC, so a failure there is their config, not the
|
|
178
|
+
temperament.
|
|
179
|
+
|
|
180
|
+
The most defensible use today is not "a more human assistant". It is
|
|
181
|
+
population diversity: many agents working on the same problem with decorrelated
|
|
182
|
+
styles of attack.
|
|
183
|
+
|
|
184
|
+
## Roadmap
|
|
185
|
+
|
|
186
|
+
1. ~~Distinguishability and stability eval.~~ Done, and it cut the claim down:
|
|
187
|
+
`eval/REPORT.md`. The open part is a judge from a different family, longer
|
|
188
|
+
tasks, and a bigger model.
|
|
189
|
+
2. ~~Second implementation in another language.~~ Done: `rust/`, byte-identical
|
|
190
|
+
to the reference over 120 seeds, and over 3000 events per seed.
|
|
191
|
+
3. Verified host adapters. One host done (pi), the protocol covered by a
|
|
192
|
+
selftest; the rest is other people's config.
|
|
193
|
+
4. Public commitment log for level 1 attestation.
|
|
194
|
+
5. A semantic development proposal that survives the constraints in
|
|
195
|
+
`AGENTS.md`. 0.3 fixed the shape of the drift and left the direction as
|
|
196
|
+
noise; this item is still open.
|
|
197
|
+
|
|
198
|
+
## Two implementations, one species
|
|
199
|
+
|
|
200
|
+
`tools/parity.py` runs the Rust binary and the Python reference side by side and
|
|
201
|
+
compares the rendered text and the JSON, byte for byte, with and without
|
|
202
|
+
development events:
|
|
203
|
+
|
|
204
|
+
$ python3 tools/parity.py --seeds 120
|
|
205
|
+
parity ok: 960 comparisons over 120 seeds, 40 events each
|
|
206
|
+
|
|
207
|
+
That is stronger than the spec requires. The spec asks for equal phenotypes;
|
|
208
|
+
this also pins the wording of the rendered text, so a host can swap binaries
|
|
209
|
+
without changing who the agent is. `cargo test` includes the conformance
|
|
210
|
+
vectors, so a change that alters who an agent is fails before it ships.
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "exoself"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "An unchosen, verifiable temperament for software agents"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "exoself contributors" }]
|
|
13
|
+
keywords = ["agents", "llm", "personality", "temperament", "deterministic", "mcp"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Software Development :: Libraries",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
dependencies = []
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://cyoren.github.io/exoself/"
|
|
31
|
+
Repository = "https://github.com/cYoren/exoself"
|
|
32
|
+
Specification = "https://github.com/cYoren/exoself/blob/main/SPEC.md"
|
|
33
|
+
Changelog = "https://github.com/cYoren/exoself/blob/main/AGENTS.md"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
exoself = "exoself.cli:main"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools]
|
|
39
|
+
license-files = ["LICENSE"]
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.packages.find]
|
|
42
|
+
where = ["src"]
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.package-data]
|
|
45
|
+
exoself = ["registry/*.json", "py.typed"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
pythonpath = ["src"]
|
exoself-0.3.0/setup.cfg
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""exoself: an unchosen, verifiable temperament for software agents."""
|
|
2
|
+
|
|
3
|
+
from .core import ( # noqa: F401
|
|
4
|
+
SPEC_VERSION,
|
|
5
|
+
agent_id,
|
|
6
|
+
bind_beacon,
|
|
7
|
+
born,
|
|
8
|
+
develop,
|
|
9
|
+
load_registry,
|
|
10
|
+
new_state,
|
|
11
|
+
phenotype,
|
|
12
|
+
verify_certificate,
|
|
13
|
+
)
|
|
14
|
+
from .render import render_prompt, render_soul # noqa: F401
|
|
15
|
+
|
|
16
|
+
__version__ = "0.1.0"
|