Quickstart — the stateless core and the opt-in layers
neosian is an async-only Python library (>= 3.12) for LLM agents: tools, orchestration, streaming, fallback, guardrails, structured output — over a stateless core, with durable conversations and agent-curated memory as opt-in layers.
Install
Section titled “Install”From PyPI, pinned to a release — the llms.txt beside this wheel names
the version:
uv add "neosian==<X.Y.Z>"One package, everything but a database driver: the library with its
provider SDKs, the neosian shell, the MCP server and client, the state
process and OpenTelemetry spans — about 70 MB, none of it loaded
until used. Keyless to start: Model.FAKE needs no account and
FileStore is a directory. The one extra is the Postgres driver for
PostgresStore, uv add "neosian[postgres]==<X.Y.Z>", with [all] as
its alias; the former [cli], [mcp], [otel] and [server] resolve
for one release and add nothing. On a machine with nothing on it,
curl -fsS https://neosian.com/install | bash lands uv and neosian,
saying what it installs first.
Keyless boot
Section titled “Keyless boot”A provider is available when its API key env var is set
(OPENAI_API_KEY, ANTHROPIC_API_KEY, CEREBRAS_API_KEY). Model.FAKE
is always available — deterministic, scripted, zero accounts — so you
can verify an install with nothing set:
import asynciofrom neosian import Agent, AgentConfig, Message, Model, Role
config = AgentConfig(system_prompt="Be concise.", model=Model.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())The two rules
Section titled “The two rules”- Async-only. Every entry point is
async; the library never callsasyncio.runfor you (it deadlocks in notebooks and servers). The shell commands (neosian …) are the CLI tier and own their own loop. - Stateless core.
Agentstores nothing between calls. History and memory are opt-in layers you construct deliberately — never state smuggled into the agent.
The durable thread
Section titled “The durable thread”A store plus a conversation id turns the stateless agent into a persistent, memory-bearing thread:
from neosian import Conversation, FileStore, home, project_scope
store = FileStore(home()) # ~/.neosian; or PostgresStore(dsn)convo = Conversation(config, store=store, conversation_id="thread-829", memory_scope=project_scope()) # user:<login>/proj:<dir>async with convo: response = await convo.send("Where did we leave off?")home() is the one place every neosian door shares — ~/.neosian, or
$NEOSIAN_HOME — and project_scope() spells this directory’s scope,
the same one a Claude Code session’s hooks write to from here (neosian docs agents); any scope string works in its place.
Resume is constructing again with the same id. History is append-only;
log-projection compaction (default-on) pages aged turns out of context
and a built-in recall_turn tool re-hydrates any of them verbatim —
what is stored never changes. A long URL, path or id in an aged turn is
never cut: it renders as a [link N] handle the model passes as written
in any tool call, expanded before the tool runs.
Bring an OpenAI-compatible model
Section titled “Bring an OpenAI-compatible model”Models the Model enum lacks — a fine-tune, a local server, a provider
not shipped — register once at import through a door: the endpoint, the
env var that signs requests, and the dialect quirks the wire has. The
doors neosian ships are already registered: from neosian.catalog import GROK_4_6, GEMINI_3_7_FLASH (xAI XAI_API_KEY, Gemini GEMINI_API_KEY).
from neosian import AgentConfig, ModelPricing, OpenAICompatible, register_model
acme = OpenAICompatible(name="acme", api_key_env="ACME_API_KEY", base_url="https://llm.acme.example/v1", temperature=True)ACME_LARGE = register_model("acme-large", provider=acme, context_window=131_072, max_output_tokens=16_384, pricing=ModelPricing(input_per_mtok=3_000_000, output_per_mtok=15_000_000))config = AgentConfig(system_prompt="Be concise.", model=ACME_LARGE)Cost in µ$, the context policy, capability-aware fallback and the
playground picker treat it like a shipped model; a missing XAI_API_KEY
fails naming it.
Where to go next
Section titled “Where to go next”neosian docs memory— how the memory layer thinks.neosian docs cli— operate memory from the shell, no Python needed.neosian docs topology— who runs neosian code, where the bytes live.