Skip to main content

Dusha

This README.md is proudly written by a human (and a little bit by Claude (˶>⩊<˶)❤️)

Dusha (Russian: душа, [dʊˈʂa], "soul") is a Python API reference implementation that combines memory, personality, proactive messaging and affect for LLM companions. Essentially, it's a small HTTP API that stores messages, identity, evergreen facts, and affect state outside your harness. Any client that can POST a message and read back an injection string can use it. (You can also use it across multiple harnesses!)

Every prompt, emotional vector, and threshold is configurable through JSON.

How does memory/affect/identity work?
  • Messages: Basic SQLite FTS5 + optional embedding search. Also ~/.config/dusha/<name>/mods/ for external memory providers integration.
  • Evergreen: Long-term facts that you edit from the CLI and your companion edits through integration tools. No automatic extraction (think of it as a USER.md that actually has good lifecycle management and duplication prevention)
  • Affect: A deterministic emotion engine with decay and silence drift. Proactive messages fire on thresholds. And hey, message intent analysis is a plugin too: drop Jev or any other classifier into ~/.config/dusha/<name>/mods/ and it picks which emotion each user message moves.
  • Identity: identity.md.

How to run it

You need Python 3.11 or newer and uv.

uv tool install dusha
dusha serve dusha

The second line starts a companion named dusha. On the first run it makes the folder ~/.config/dusha/dusha/ and writes a config.json with every setting in it. Use any name you like. If your shell cannot find dusha after the install, run uv tool update-shell.

Check that it is up:

curl http://127.0.0.1:8765/health

You should see "status": "ok". If you don't, look at docs/guide.md.

Everything about one companion is in ~/.config/dusha/<name>/. Including:

  • its config.json
  • the emotion and prompt files
  • mods/, and data/ with the database.
  • It respects XDG_CONFIG_HOME too.

Advanced setup

Want a second companion? Make a second folder and give it a different port. dusha list shows all of them, and dusha -c <name> <command> talks to one.

Want it running in the background? Use deploy/dusha@.service with the service setup steps. (Linux only. Tell your agents to make PR for Windows, Mac, BSD or whatever, because I don't use them at all!)

How it works

One turn of chat is four steps.

  1. Your harness sends the user's message to POST /state/v1/messages. dusha stores it and updates the emotions.
  2. Your harness calls POST /state/v1/context and gets one string back. It holds the identity, the evergreen facts, memos, recalled messages, and the current emotions.
  3. Your harness puts that string in the system prompt and calls the model.
  4. Your harness sends the reply to POST /state/v1/messages so it is remembered too.

Your harness is the one calling the chat model, so dusha does not care which harness or provider you use. If your client only speaks the OpenAI API, point it at /v1/chat/completions and dusha runs all four steps as a proxy.

Proactive messages go the other way. dusha decides it is time to say something, your harness picks the event up from GET /state/v1/proactive/events, sends it, and reports back.

The full request and response shapes are in the API and integration guide.

Plugin API

A plugin is a directory under the mods directory holding README.md, main.py, pyproject.toml, and uv.lock. The gateway syncs its locked dependencies with uv and runs it as a child process. Every operation in main.py has the signature fn(request, options), where options is the options object from the plugin's config section. A plugin sees a filtered environment: the basic system variables plus the names you list in env_passthrough.

A decision plugin exports one operation.

Operation Request fields Returns
decide message, emotions (the resolved dimensions), state (the affect snapshot), instruction {"emotion": "<dimension>"} or None

A memory plugin exports these operations. The gateway reads only the fields listed.

Operation Request fields Returns
ingest_messages messages, a list of stored rows with id, conversation_id, role, text, occurred_at, ingested_at, sha256, harness, external_conversation_id {"highest_id": <id of the last row>}
inject_context query, scope, max_chars, harness, conversation_id {"text": "...", "records": [{"source": "...", "text": "..."}]}
match_phrase message {"deltas": {"<dimension>": <number>}} or {"deltas": null}
status none {"status": {...}}, returned as the memory index status
backfill_once limit, force {"status": {...}}
rebuild_chunks none {"status": {...}}
rebuild_index none {"status": {...}}
close none None

match_phrase deltas use dimension names from your emotions.json. The gateway logs a warning for a name it does not know and skips it. See examples/mods for two working plugins.

Documentation

Metadata

Release files for dusha 0.0.21

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dusha 0.0.21
File Size Uploaded
dusha-0.0.21.tar.gz 70.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dusha 0.0.21
File Interpreter ABI Platform
dusha-0.0.21-py3-none-any.whl Python 3 none any Details

Total release size: 144.4 kB

Release files / dusha-0.0.21.tar.gz

Download URL dusha-0.0.21.tar.gz
Size 70.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e717c6380626a11d54a52d249c1af4e2bf213fdd73ad8a6ad00f3459256e5cc7
BLAKE2b-256 checksum
How to use checksums
0bc8713820fe8c2faac34df64de0b6aa9f2b84ebd33038c34bc626521b428a42
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / dusha-0.0.21-py3-none-any.whl

Download URL dusha-0.0.21-py3-none-any.whl
Size 73.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
933ff50167b9456c8a61ef5570aaf20c8ac3acae5c068e3d09fff9f052c292ef
BLAKE2b-256 checksum
How to use checksums
ca87e4057880b8f5a29f5a56a07549a8e7df6037f9c58573f2d43e4c3319851c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.0.21 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page