This release is a pre-release and may not be stable for production use.
neosian
The state layer for LLM agents: durable conversations, agent-curated memory, skills, a shared board and a ledger of who did what — on storage you own (a directory, your Postgres, or one small state process), for the agent you already use or the one you build.
Two doors, one store:
- Build an agent. An async-only, stateless
Agent(tools, streaming, fallback, guardrails, structured output) that aConversationwraps into a durable, memory-bearing thread. - Give your agent state. Claude Code, Codex, Cursor or OpenCode get
memory and skills over MCP and every session recorded through hooks —
neosian mcp install --client claude-code,neosian record install.
A Claude Code session landing as a recorded turn that neosian audit
names, and the next session opening on where we left off — no key of
yours, no flags: the home and this project's scope.
Agents read this repository too: llms.txt is the machine
front door, neosian docs prints the shipped docs pages from the wheel
(version-true), and every shell verb has --json and exit tiers.
store = FileStore(home()) # ~/.neosian, or your PostgresStore(dsn)
convo = Conversation(config, store=store, conversation_id="thread-829",
memory_scope=project_scope()) # user:<login>/proj:<dir>
response = await convo.send("Where did we leave off?")
Install
Requires Python >= 3.12. On PyPI as a pre-release until v1.0.0, so pin it explicitly (extras ride the same pin):
uv add "neosian==1.0.0rc2"
uv add "neosian[postgres]==1.0.0rc2" # + PostgresStore
uv add "neosian[mcp]==1.0.0rc2" # + MCP server and client
uv add "neosian[otel]==1.0.0rc2" # + OpenTelemetry spans
uv add "neosian[server]==1.0.0rc2" # + the state process
uv add "neosian[cli]==1.0.0rc2" # + the `neosian` shell
The core install carries no terminal library, no database driver, no MCP
SDK and no server: the neosian console script rides [cli], while the
python -m doors (neosian.memory, neosian.record, neosian.mcp,
neosian.server) need no extra. The three provider SDKs (openai,
anthropic, cerebras) come unconditionally — a provider is available
when its API key is set.
For a machine with nothing on it, the one-liner is
scripts/install.sh: uv present or installed
from a pinned release, uv tool install "neosian[cli]", the PATH check,
and the registration command printed. It is the same two commands,
spelled out beside it:
curl -fsS https://neosian.com/install | bash
# or, by hand:
curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install "neosian[cli]==1.0.0rc2"
To work on neosian itself, uv sync --all-groups then uv run neosian version (the Development section has the gates).
Quickstart
Keyless boot is an invariant: Model.FAKE is always available, so an
install verifies with no account. The fake is scripted through the
client_factory seam — the same seam the unit tier and the eval
baseline use:
import asyncio
from neosian import Agent, AgentConfig, Message, Model, Role
from neosian.fake import FakeClient, FakeScript, FakeTurn
fake = FakeClient(FakeScript(turns=(FakeTurn(content="hello from the fake"),)))
config = AgentConfig(system_prompt="Be concise.", model=Model.FAKE,
client_factory=lambda _: fake)
async def main() -> None:
response = await Agent(config=config).run(
[Message(role=Role.USER, content="hello")], stream=False
)
print(response.message.content)
asyncio.run(main())
Set a key and name a real model (model=Model.CLAUDE_SONNET_5, the
providers table below); tools are decorated functions whose signature is
the schema (neosian docs tools). examples/ has one runnable
file per feature, every one importing keylessly.
What is in the box
Each line is one page in the wheel — neosian docs <topic>.
- Conversation and memory (
memory). History is an append-only log; log-projection compaction pages aged turns out of context andrecall_turnre-hydrates any of them verbatim — paging, not deletion. Memory is file-school: small markdown documents with frontmatter under mounted scopes, read and written through onememorytool (view,create,str_replace,insert,delete,rename); reflection at the close distills the session into deliberate writes. Every write is a full-content version row with an actor; amemory_writeframe on the stream carries{command, path, version}so a host renders "remembered X" with a workingrevert_memoryundo. - The shell and the ledger (
cli). The six memory commands, the gardener (maintain), the operator verbs (versions,redact,revert),audit— what was done, by whom, when, on any substrate — andexport/import, which move a store whole, history included. - Skills (
skills). A skill is a document underskills/<name>in a mount: versioned, curated by the mount flag, loaded bylist_skills/load_skill, served over MCP as a prompt (a slash command in Claude Code). - MCP, both directions (
mcp).python -m neosian.mcpserves the store to any client over stdio;McpServer.stdio/http/in_processconsumes any MCP server as agent tools — schema verbatim,is_errorin-band, the approval gate and hooks unchanged. - The agent you already use (
agents).neosian record installspells the hooks that land a prompt-to-stop span as one turn byclaude-code:<session>(Codex and OpenCode too), plus a sessions document;SessionStartprints the index and "where we left off" into the next window. A neosianConversationon the same home shares the scope, so oneauditnames both. - The state process (
topology).neosian serveputs memory and conversations on a port (theserverextra; the shipped Dockerfile is the appliance) — reach, not capability;RemoteStoredrops in whereFileStoredoes, core install. Bearer tokens env-only, per-client when you want the ledger to know who wrote. - The agent core (
agent,tools).run(stream=True)yields ten frozenAgentEventdataclasses a host relays over SSE;AgentHooksobserve every turn, call and tool;ToolGateConfigroutes every tool call through one approver, and no decision is a denial; capability- aware fallback, guardrails on any model, structured output, prompt caching, multimodal blocks on Anthropic.
Providers
API keys are read from environment variables; a provider is available when
its key is set (asking for an unavailable model raises
MissingAPIKeyError).
| Provider | Env var | Notes |
|---|---|---|
| OpenAI | OPENAI_API_KEY |
GPT-5 family (reasoning models) |
| Anthropic | ANTHROPIC_API_KEY |
Claude; vision/PDF input, prompt caching, adaptive thinking |
| Cerebras | CEREBRAS_API_KEY |
Default provider (gpt-oss-120b) |
| xAI | XAI_API_KEY |
grok-4.6 — a shipped door row (from neosian.catalog import GROK_4_6) |
| Google Gemini API | GEMINI_API_KEY |
gemini-3.7-flash on the OpenAI-compatible endpoint (GEMINI_3_7_FLASH) |
| Fake | — | Keyless, deterministic, always available (Model.FAKE) |
| A registered door | the door's api_key_env |
Any OpenAI-compatible endpoint via register_model (neosian docs quickstart) |
Every shipped row is earned by green dispatched runs of the memory
baselines; membership is measured, never assumed
(neosian docs baselines).
Storage
MemoryStore and ConversationStore are the contracts: async ABCs that
own no connection, commit no transaction, issue no DDL. FileStore (a
plain directory), PostgresStore (the postgres extra; schema by
python -m neosian.schemas postgres | psql "$DSN") and RemoteStore
(the state process's wire) implement both; a host may implement its own,
kept honest by the shipped MemoryStoreContract /
ConversationStoreContract conformance kits. One writer per FileStore
root; many workers on one Postgres.
Evaluation
neosian eval suite.yaml runs YAML suites and exits nonzero on failure —
an agent suite over variants × models × cases, and kind: memory, which
scores store truth across scripted sessions on every transport. The
shipped memory pack is all-green on models: [fake], and the same pack
against the real providers produces the
baselines page,
fingerprint-gated so a prompt change without a recorded re-run fails
make test.
Stability
v1.0.0 is deliberately not yet cut. When it is, it will carry the API
stability promise: Agent, Conversation, MemoryStore, and the
neosian.evaluation facade stable under SemVer, the ecosystem
seams (scope grammar, token classes, integer
micro-USD, event vocabulary, error codes) SemVer-guaranteed — a seam break
only at a major — and the state process's wire (the twelve /v1/ store
routes and their envelope, versioned by WIRE_VERSION) stable under the
same promise: one promise covering library, seams, and wire. Until then the seams are append-only by convention, and error
codes are already append-only forever. Consumers pin a release
(neosian==X.Y.Z), never master.
Development
make install # uv sync --locked --all-groups
make lint # ruff + black --check + import-linter
make typecheck # mypy --strict neosian tests examples
make test # unit tier — the default gate, zero API keys
make size # file-size gate (warn 300 / fail 500)
make test-external provider=anthropic file=~/path/to/creds # real API calls
make test-postgres # needs NEOSIAN_TEST_POSTGRES_DSN
make test-container # both kits vs the container (docker)
The default gate needs no accounts; external tiers inject credentials
value-blind. Sign off every commit (git commit -s): contributions are
accepted under the Developer Certificate of
Origin and licensed as the project
is, Apache-2.0 — there is no CLA. Open an issue before a feature or a
departure from documented behaviour; the public API is pinned by
tests/unit/test_init.py, so an export change is a reviewed diff.
SECURITY.md is where vulnerabilities go, never an issue.
Documents
neosian docs <topic>— the shipped pages, from the wheel:quickstart,agent,tools,memory,skills,cli,mcp,agents,topology,baselines(the published per-provider memory numbers).- SERVICES.md — every env key and what turning it off means.
- CHANGELOG.md — Keep a Changelog, one section per release.
- SECURITY.md — where to report, and the supported line.
- llms.txt — the machine-readable front door (byte-identical twin ships in the wheel).
Be kind and constructive in every project space; the maintainers read community@neosian.com.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file neosian-1.0.0rc2.tar.gz.
File metadata
- Download URL: neosian-1.0.0rc2.tar.gz
- Upload date:
- Size: 866.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0c5bcb04ed8a10ac868bc8db16f9f213d18c672a84d8e927f500edbcb9e0f75
|
|
| MD5 |
f2164a37ffdc76879b688d7b32456edd
|
|
| BLAKE2b-256 |
2947e93cfbc27cc541c9b5b4fdf8ec0d1e9fd14f6817fd5f0321181f00cb215f
|
File details
Details for the file neosian-1.0.0rc2-py3-none-any.whl.
File metadata
- Download URL: neosian-1.0.0rc2-py3-none-any.whl
- Upload date:
- Size: 508.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
69012c7604c15c06b324f40bf39781e1e2b647addd0f7e993aa980e138192bc6
|
|
| MD5 |
de5c44a00cf77fdcae14db309e22bfff
|
|
| BLAKE2b-256 |
d1166332b5b9954977a4960481885f6f91c9a3dc13934f7f1a06396b0a0e43a0
|