# 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 `recall_turn`. 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 | tools | memory | skills | cli | mcp | agents | topology`
  — one page, markdown on stdout, pipe-safe.
- `neosian docs topology` — who runs neosian code x where the bytes live;
  one writer per FileStore root.

## Operate memory from the shell

- `neosian memory view / --scope user:me` — the first command to try;
  renders the memory index. 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/<name>` 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 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.
- 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; Codex is print-only — apply with the printed
  `codex mcp add` line).
- `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), and `recall_turn(turn, conversation)` —
  any recorded turn of any agent's session, verbatim.
- The other direction: `async with McpServer.stdio(cmd, args) as s:`
  (or `.http(url, headers=)`, `.in_process(server)`) from `neosian.mcp`
  — 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`).

## Record a foreign agent

- `neosian record install --client claude-code|codex|opencode` prints
  the four hooks — no flags: the home and this directory's layout,
  `user:<login>` at /user and `user:<login>/proj:<slug>` at /project,
  spelled into the line; `--root DIR --scope S` override (the events:
  UserPromptSubmit, PostToolUse, Stop, SessionStart) — for OpenCode, a
  plugin file; `--write` merges them into
  ./.claude/settings.json or ./.codex/hooks.json, every other hook
  preserved, or writes ./.opencode/plugins/neosian-record.js (Codex: a
  trusted project, hooks reviewed in /hooks).
- The hooks call `python -m neosian.record` with the payload on stdin; a
  prompt-to-stop span lands as one turn by `claude-code:<session_id>` in
  the conversation the session id names, plus a sessions document at
  /memories/sessions/<session_id>. Read it back: `neosian audit --scope S
  --conversation <session_id>`. 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) or Postgres. `neosian docs agents` carries the client table.

## Reach it over the network

- `NEOSIAN_SERVE_TOKEN=... neosian serve` — 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,...` — 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`.
- Python clients: `await RemoteStore.connect(url, token=...)` — both
  storage ABCs over the wire, core install, drops in where FileStore
  does. `neosian docs topology` carries the full shape.

## 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"),
  ...)` — once at import; the model prices in µ$ and passes every gate
  like a shipped one. `neosian docs quickstart` carries the snippet.
- Shipped door rows — `from neosian.catalog import GROK_4_6,
  GEMINI_3_7_FLASH` (xAI `XAI_API_KEY`; Gemini `GEMINI_API_KEY`):
  first-party, fingerprinted, no client of their own; each earned by
  green dispatched runs of the memory baselines.

## Install

- `uv add "neosian==1.0.0rc3"` — 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); the former `[cli]`, `[mcp]`,
  `[otel]`, `[server]` resolve for one release and add nothing.
- `curl -fsS https://neosian.com/install | bash` — 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.0rc3` — the state
  process on a volume, `/health` the one open route.

## Docs

- https://github.com/mausa-ai/neosian/blob/v1.0.0rc3/README.md: install and quickstart.
- https://github.com/mausa-ai/neosian/blob/v1.0.0rc3/SERVICES.md: every environment key and what turning it off means.
- `neosian docs baselines`: the published per-provider memory numbers.
