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:
- Give your agent state. Claude Code, Codex, OpenCode, Muse Code or
interactive Cursor get memory and skills over MCP and every session
recorded through hooks:
neosian setup --writewires every client it finds, once per machine;neosian statussays whether the machine is set up; bareneosianopens a chat with an agent that knows neosian, on the same memory. - Build an agent. An async-only, stateless
Agent(tools, streaming, fallback, guardrails, structured output) that aConversationwraps into a durable, memory-bearing thread.
Set up once per machine, every session lands in the ledger: neosian audit names the turn, the next session opens on where we left off, and
neosian search finds it by its words.
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 — one
CLI for humans and agents (neosian docs cli).
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. One package, everything in it. Pin the release:
uv add "neosian==1.0.3"
The install brings the library with its two provider SDKs (OpenAI and
Anthropic — Cerebras, xAI and Gemini ride the OpenAI wire), the neosian
shell, the MCP server and client, the state process and OpenTelemetry
spans: about 70 MB on disk, none of it loaded until used. Nothing in
it needs an account or a server to start — Model.FAKE runs keylessly
and FileStore is a directory. The one extra is the Postgres driver,
uv add "neosian[postgres]==1.0.3", for a PostgresStore against a
server you already run; [all] is its alias.
For a machine with nothing on it, the one-liner is
scripts/install.sh: it says what it
installs, finds uv or installs it from a pinned release, runs uv tool install neosian, checks the PATH and prints the registration command.
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==1.0.3"
To work on neosian itself, uv sync --all-groups then uv run neosian version (the Development section has the gates).
One store under many agents
neosian setup --write connects your installed clients to the home once.
Their hooks record each session into one store, so any of them picks up
where another stopped, and one ledger names them all.
Claude Code records the work, Codex picks it up, one audit names both. A memory write becomes a plain markdown document you can read, version and revert.
Build an agent
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,search_historyfinds any turn by its words andrecall_turnre-hydrates it 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 —search— the turns holding every term, newest first — 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, OpenCode, Muse Code and interactive Cursor too), plus a sessions document;SessionStartprints the index and "where we left off" into the next window. Registered once per machine, every project gets its own scope with no file of its own. A neosianConversationon the same home shares the scope, so oneauditnames both. - The state process (
topology).neosian serveputs memory and conversations on a port (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. - Under your own agent (
interop).tool_definition(tool)is the definition any neosian tool sends to the model and the tool itself the executor, so the memory tool runs under a pydantic-ai or OpenAI Agents SDK agent (two runnable examples, keyless in the unit tier) or over MCP from any language; the data stays a directory you can grep, git and leave with. - Your own store (
stores). The two storage ABCs and their constraints in plain words, the shipped conformance kits as the certification standard, andexamples/sqlite_store.py, a third substrate that passes both kits and stays community custody.
Providers
API keys are read from environment variables; a provider is available when
its key is set (asking for an unavailable model raises
MissingAPIKeyError). For the shell, neosian configure stores any of
them under the home and loads them where the environment has none.
| Provider | Env var | Models |
|---|---|---|
| A registered door | the door's api_key_env |
The day-one door for any model neosian has not shipped: any OpenAI-compatible endpoint via register_model (neosian docs quickstart) |
| Local (llama.cpp, Ollama) | none: api_key_env=None |
A door that signs nothing, on a zero card; the llama.cpp and Ollama recipes and the measured local row (neosian docs local) |
| OpenAI | OPENAI_API_KEY |
gpt-6-sol (default), gpt-6-astra, gpt-6-luna, gpt-5.1 (reasoning, max effort), on the Responses API with reasoning carried through tool loops and nothing stored at the provider |
| Anthropic | ANTHROPIC_API_KEY |
claude-fable-5-1, claude-opus-5-5, claude-sonnet-5 (default); vision/PDF input, prompt caching, adaptive thinking |
| Cerebras | CEREBRAS_API_KEY |
Default provider: gpt-oss-120b, qwen-3.8-27b |
| xAI | XAI_API_KEY |
grok-4.6 — a shipped door row (Model.GROK_4_6), on the Responses API |
| Google Gemini API | GEMINI_API_KEY |
gemini-3.8-flash, gemini-3.7-flash on the OpenAI-compatible endpoint (Model.GEMINI_3_8_FLASH; the introductory card through 2026-12-31) |
| Moonshot | MOONSHOT_API_KEY |
kimi-k3: a shipped door row (Model.KIMI_K3), always reasoning |
| Alibaba Model Studio (Singapore) | DASHSCOPE_API_KEY |
qwen3.8-max: a shipped door row (Model.QWEN_3_8_MAX); thinking on when a reasoning_effort is asked |
| Fake | — | Keyless, deterministic, always available (Model.FAKE) |
Every shipped row is a Model member and answers to its wire id too
(AgentConfig(model="gpt-6-sol")); each carries its provider's
lifecycle as data (Model.X.spec.retires, card_until) and 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 (neosian docs stores: the
contract, the kits, a worked SQLite example that passes both). 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. A suite
names its agent file relative to itself, so it runs from any directory;
--json prints the artifact and --output DIR places it. 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 carries 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, with a seam break only
at a major, and the state process's wire (the nineteen /v1/ routes and
their envelope, neosian docs wire, versioned by WIRE_VERSION) stable
under the same promise: one promise covering library, seams, and wire.
Error codes are append-only forever. Consumers pin a release
(neosian==X.Y.Z), never master. Model ids follow their providers'
lifecycles: a retired id leaves in the next release after its provider's
date, named in the changelog; each shipped row's clock is data on its
spec (neosian docs baselines).
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,memory,skills,stores(author and certify your own store),agents,cli,mcp,interop(memory under pydantic-ai or the Agents SDK),agent,tools,local(llama.cpp and Ollama on the door),topology,wire(the state process's HTTP contract),baselines(the published per-provider memory numbers); the same pages online at neosian.com/docs, rendered from the wheel at the current release.- 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.
Metadata
Release files for neosian 1.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| neosian-1.0.3.tar.gz | 1.2 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| neosian-1.0.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.8 MB
Release files / neosian-1.0.3.tar.gz
| Download URL | neosian-1.0.3.tar.gz |
|---|---|
| Size | 1.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f621c31cc8e52b31583838e20471e57eed86aa265695b3badf00f6a208ea18a7
|
|
BLAKE2b-256 checksum How to use checksums |
3c1c1984a96fbe6b43897a3ebe4a7b99e0712b3ee1453a3745937ba5e20d5b46
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / neosian-1.0.3-py3-none-any.whl
| Download URL | neosian-1.0.3-py3-none-any.whl |
|---|---|
| Size | 670.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cf87e393587b1f3fbe3320a49e23977a77554c97457f6e82f00db12a20980802
|
|
BLAKE2b-256 checksum How to use checksums |
d6d05c6566bb82bc8b9e360aae6940e79eae974f4bedac42bf18a845b8ca3b02
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Security for neosian 1.0.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.