# neosian > Async-only Python state layer for LLM agents: durable conversations, > agent-curated file-shaped memory, and context lifecycle, on storage the > product owns. Keyless to boot; Python >= 3.12. A stateless `Agent` core (tools, orchestration, streaming, fallback, guardrails, structured output) with opt-in `Conversation` and memory layers. One memory dispatcher serves five transports: the function tool, Anthropic's native declaration, an MCP stdio server, the shell, and the state process's HTTP wire. Agents share context by config: a `board` mount on a task scope, and read-only `ConversationView`s of another conversation with cross-conversation `search_history` and `recall_turn`; a Conversation with a `/project` mount lists itself under `sessions/`, so one search covers a project's sessions, foreign and neosian alike. Long URLs, paths and ids in aged turns become `[link N]` handles, expanded at the tool boundary. Skills are documents under `skills/` in a mount: versioned, curated by the mount flag, loaded by `list_skills`/`load_skill`, served as MCP prompts. `McpServer` consumes any MCP server as agent tools, over stdio or HTTP. ## Learn from the shell - `neosian docs`: list the shipped topics (they travel in the wheel, so they always describe the installed version). - `neosian docs quickstart | agent | local | tools | memory | skills | stores | cli | mcp | agents | interop | topology | wire` prints one page, markdown on stdout, pipe-safe. - `neosian docs topology`: who runs neosian code x where the bytes live; one writer per FileStore root. - The same pages online, rendered from the wheel at the current release: https://docs.neosian.com (this file at https://docs.neosian.com/llms.txt). ## Set up from the shell (the human path) - `neosian status [--json]`: is this machine set up? The home, which providers have a key (never values), this directory's two scopes, per client installed / MCP registered / hooks present / level (user, project, both) / interpreter resolving, the last recorded session, the install shape. Exit 0 always; findings are data. - `neosian setup [--write] [--level user|project] [--root DIR | --url URL]`: wire every installed client (Claude Code, Codex, OpenCode, Muse Code, Cursor) to the home, once per machine: MCP + the record hooks in the client's own config, no file per project; print first. `--write` runs the client's own CLI for a file it owns (`claude mcp add-json`, `codex mcp add`) when on PATH, else prints the line and exits 1. `--url URL` moves every client to the state process in one run. - `neosian configure --list | --provider NAME --key - | --env NAME --key - | --delete`: keys under `/config.toml`, read from stdin, never argv; `--env` names a door by its key's env var (one an agent file registers). - `neosian chat [PROMPT] [--model M] [--agent FILE] [--resume ID] [--json]`: the resident agent that knows neosian (a `docs` tool over these pages) on the same memory; a PROMPT or piped stdin is one turn, `--model fake` keyless. `[[chat.mcp]]` tables in `/config.toml` (`name`, then `command`/`args`/`env` or `url`/`headers`, `prefix`) are MCP servers it opens for the session, their tools added. Bare `neosian` on a terminal opens it. - `neosian update [--mode off|notify|auto]`: a PyPI check on the human verbs only, never on an agent verb; `auto` applies a uv tool install within the major. ## Operate memory from the shell - `neosian memory view /`: the first command to try; renders the memory index. No flags inside a project means this directory's layout (`/user`, `/project`); `--scope S` or `NEOSIAN_SCOPE` names a scope. The store is the home, `~/.neosian` or `$NEOSIAN_HOME`, unless `--root DIR`, `--url` or the DSN names one. - Six commands: view, create, str_replace, insert, delete, rename. `--json` prints the memory tool's result envelope verbatim. - `neosian memory maintain`, the gardener: keyless dedup + empty-prune; `--model MODEL` adds the semantic pass (merge, prune stale, promote). - A skill is `create /project/skills/` with a frontmatter `description` and the instructions as the body (`neosian docs skills`); `versions` and `revert` work on it like any document. - Operator verbs, keyless: `versions PATH` (the audit trail; `--json` carries full historical content), `redact PATH [--all]` (the one eraser; audit skeleton preserved), `revert PATH --version N` (undo). - `neosian audit --scope S [--conversation C] [--actor A] [--since T] [--json]`, the ledger: what was done, by whom, when, newest first, identical on a root, Postgres, or the state process (`--url`). - `neosian search TERMS... [--conversation ID]... [--limit N] [--json]`: the turns holding every term, newest first, across every conversation the store holds; identical on every substrate. - `neosian export DIR` / `neosian import DIR`: a store moves whole, history included, any substrate to any other; DIR is a FileStore root. An import needs every scope and conversation empty in the target. - Exit tiers: 0 success, 1 ran-and-failed, 2 bad invocation, 130 interrupt. stdout carries the artifact; stderr carries guidance; with `--json` in argv a tier-2 error is also one `{"error": "usage"}` object. - Postgres arrives only via the NEOSIAN_POSTGRES_DSN environment variable (never an argv flag). `python -m neosian.memory` is the PATH-free twin. ## Upgrade to MCP - `neosian mcp install --client claude-code|claude-desktop|cursor|codex|opencode` prints the exact registration; `--write` applies it (refused when the client is not installed). Once per machine by default: the entry names the store and no mount, the server derives each session's layout from the directory the client spawns it in (/user alone where that has no name); `--level project` writes this directory's file with its layout in the line (not for claude-desktop, cursor, codex: one file each). Claude Code's user scope and Codex are print-only, their own CLIs write those files: apply with the printed `claude mcp add-json --scope user` / `codex mcp add` line, or let `neosian setup --write` run it. - `python -m neosian.mcp --root DIR --scope user:me` serves the same store over stdio: the `memory` tool, `list_skills` and `load_skill` over the mounts' skills (each skill also an MCP prompt, a slash command in Claude Code), `recall_turn(turn, conversation)` for any recorded turn of any agent's session, verbatim, and `search_history(query, conversation=)` for the turns holding every term, newest first. - The other direction: `async with McpServer.stdio(cmd, args) as s:` (or `.http(url, headers=)`, `.in_process(server)`) from `neosian.mcp` gives the server's tools as `AgentConfig(tools=[*s.tools])`, schema verbatim, `is_error` in-band, `prefix=` for two servers that clash; the gate and hooks apply unchanged (`neosian docs mcp`). - Under your own agent: `tool_definition(memory_tool)` is the definition any framework can carry (name, description, JSON Schema) and the tool itself the executor; `examples/interop_pydantic_ai.py` and `examples/interop_openai_agents.py` run it under pydantic-ai and the OpenAI Agents SDK, keyless in the unit tier (`neosian docs interop`). ## Record a foreign agent - `neosian record install --client claude-code|codex|opencode|muse-code|cursor` prints the client hooks (UserPromptSubmit, PostToolUse, Stop, SessionStart; Cursor has five native events below; OpenCode has a plugin file). Once per machine by default: the line names the home and no mount, and each session gets `user:` at /user and `user:/proj:` at /project, derived from the client's project directory (Claude Code: `--project "$CLAUDE_PROJECT_DIR"`); `--write` merges them into ~/.claude/settings.json or ~/.codex/hooks.json, every other hook preserved, or writes plugins/neosian-record.js in OpenCode's config directory (Codex reviews a new hook once in /hooks). `--level project` writes this directory's file with its layout in the line; `--root DIR --scope S` override at either level. One level per client: clients merge hook sources, so a user-level `--write` removes this directory's old entry and a project-level install beside user-level hooks is refused. - The hooks call `python -m neosian.record` with the payload on stdin; a prompt-to-stop span lands as one turn by `claude-code:` in the conversation the session id names, plus a sessions document at sessions/ in the mount at /project. Read it back: `neosian audit --scope S --conversation `. On SessionStart the verb prints the memory index and "where we left off" (the recent sessions, log-projected): the client adds a hook's stdout to the model's context. - Hooks beside an MCP server are two writers: use `--url` (the state process; `neosian setup --url URL --write` moves the whole machine) or Postgres. `neosian docs agents` carries the client table. ## Reach it over the network - `NEOSIAN_SERVE_TOKEN=... neosian serve` runs the state process on the home (`--root DIR` another root): memory and conversations on a port, MCP over streamable HTTP at /mcp when started with mounts. Token is env-only (one token, or a per-client table `actor=token,...`, so the process records who wrote); unset refuses to start; /health is unauthenticated. Shell clients: `--url URL` + NEOSIAN_CLIENT_TOKEN. - The shipped Dockerfile is the appliance: `docker run -e NEOSIAN_SERVE_TOKEN=... -p 6367:6367 -v state:/data neosian`. - Cursor: `setup --client cursor --write` adds native version-1 hooks at ~/.cursor/hooks.json beside user MCP. Interactive CLI 2026.09.10-fd3934a records as cursor:; --print lacks the full event stream. Completed turns wait for stop and afterAgentResponse in either order. sessionStart returns JSON additional_context. One workspace root selects /project; ambiguous roots use /user unless a project or scope is named. Imported Claude recorder calls carrying cursor_version are ignored. MCP credentials use ${env:NAME} references; hooks inherit the environment. - Muse Code: `--client muse-code`; user MCP and hooks share $XDG_CONFIG_HOME/muse/settings.json (default ~/.config/muse), schema_version 1; project MCP uses shared .mcp.json, hooks .muse/hooks.json (workspace trust required). Muse clears child environments: --url/Postgres hooks require user-level managed neosian-hooks.json and pass credential names through managed_hooks_env_vars; MCP uses ${NAME} env references. Another managed pointer is refused, never replaced. Shared project MCP survives user install; mcp_shadowed_by reports its override. Hook print mode is a files change map, with no unrelated settings. Actor muse-code:. - Python clients: `await RemoteStore.connect(url, token=...)` carries both storage ABCs over the wire, core install, drops in where FileStore does. Listings cross in pages of at most 500 rows, followed for you; `Pageable` pages them yourself. `neosian docs topology` carries the full shape. - `neosian docs wire` is the HTTP contract a client in any language implements: the nineteen /v1/ routes, the envelope, paging, the JSON shapes, WIRE_VERSION. ## Bring an OpenAI-compatible model - `register_model("acme-large", provider=OpenAICompatible(name="acme", api_key_env="ACME_API_KEY", base_url="https://llm.acme.example/v1"), ...)` is the day-one door for any model neosian has not shipped: once at import; the model prices in µ$ and passes every gate like a shipped one. `wire="chat"` (Chat Completions, the default) or `"responses"` (the Responses API, stateless: encrypted reasoning carried on the message between tool calls, nothing stored at the provider); the chat dialect knobs and `thinking_switch` beside it. `neosian docs quickstart` carries the snippet. - A local server is the same door declared keyless: `OpenAICompatible(name="local", api_key_env=None, base_url="http://127.0.0.1:8080/v1")` reads no variable and sends the SDK a placeholder, never a key of yours; price it on a zero card (`ModelPricing(input_per_mtok=0, output_per_mtok=0)`, priced at zero rather than unknown). `neosian docs local` carries the llama.cpp and Ollama recipes (`llama-server -hf ggml-org/gemma-4-E4B-it-GGUF:Q4_0 --jinja`, `ollama pull gemma4:e4b`) and the measured local row; `examples/local_agent.py` is the runnable form. - Every shipped row is a `Model` member, the door rows too: `Model.GROK_4_6` (xAI `XAI_API_KEY`), `Model.GEMINI_3_8_FLASH` (Gemini `GEMINI_API_KEY`), `Model.KIMI_K3` (Moonshot `MOONSHOT_API_KEY`), `Model.QWEN_3_8_MAX` (Alibaba Model Studio `DASHSCOPE_API_KEY`): first-party, fingerprinted, no client of their own; each earned by green dispatched runs of the memory baselines and carrying its provider's clock (`spec.retires`, `spec.card_until`). OpenAI's rows (`gpt-6-sol` the default, `gpt-6-astra`) and xAI's speak the Responses API. A config takes the wire id too: `AgentConfig(model="gpt-6-sol")`. ## Install - `uv add "neosian==1.0.0rc20"`: one package, the library and its provider SDKs, the `neosian` shell, the MCP server and client, the state process and OpenTelemetry spans (about 70 MB; nothing loaded until used). On PyPI as a pre-release until v1.0.0: pin it explicitly, never a default resolve. Keyless to start: `Model.FAKE` and `FileStore` need nothing. The one extra is the Postgres driver for `PostgresStore`, `neosian[postgres]` (`[all]` its alias). - `curl -fsS https://neosian.com/install | bash` puts uv and neosian on a machine with nothing on it; the script says what it installs first. - The appliance: `docker run -d -e NEOSIAN_SERVE_TOKEN=… -p 6367:6367 -v neosian-state:/data ghcr.io/mausa-ai/neosian:1.0.0rc20`, the state process on a volume, `/health` the one open route. ## Docs - https://github.com/mausa-ai/neosian/blob/v1.0.0rc20/README.md: install and quickstart. - https://github.com/mausa-ai/neosian/blob/v1.0.0rc20/SERVICES.md: every environment key and what turning it off means. - `neosian docs baselines`: the published per-provider memory numbers.