Skip to main content

soothe-nano

PyPI version Ask DeepWiki

A ready-to-run coding agent you can drop into a script, CLI, or app.

Built on soothe-deepagents (filesystem, shell, subagents, skills, MCP). Nano adds the pieces you usually wire yourself: workspace safety, progressive tools/skills, research subagents, and a config-driven factory.

Vision

Give builders a production-shaped SootheNanoAgent in a few lines of Python.

  • Start small — chat, tools, or full composition
  • Stay portable — embed in notebooks, CLIs, or your own service
  • Compose what you need — tools, memory, subagents, skills, and MCP via config

Architecture

soothe-deepagents   agent harness (FS, shell, memory, skills base)
        ↓
soothe-sdk          shared contracts (protocols, events)
        ↓
soothe-nano         SootheNanoAgent + toolkits + subagents + MCP
create_nano_agent(config)
        │
        ├─ model + middleware stack
        ├─ tools (builtin groups + yours)
        ├─ subagents (planner, research, browser, …)
        ├─ skills (progressive discovery)
        └─ MCP (on-demand activation)

Features

Area What nano provides
Tools Builtin groups: shell, file ops, HTTP, search, data, image, …
Subagents Ready: plan, deep/academic research, browser
Skills / tools in context Progressive loading — activate what the turn needs
Workspace Scoped workspace + security defaults
Config YAML / SootheConfig factory
Memory Optional long-term memory via protocols
MCP Registry and on-demand adapters

vs deepagents

deepagents soothe-nano
What you get Opinionated harness Harness plus coding product defaults
Tools Bring your own Builtin groups out of the box
Subagents You define them Ready plan / research / browser
Skills / tools in context Base support Progressive loading
Workspace Pluggable backends Scoped workspace + security defaults
Config Code-first YAML / SootheConfig factory

Use deepagents when you want a minimal harness and full control.
Use nano when you want a coding agent that already knows how to work in a repo.

When to use nano

Scenario Fit
Coding assistant in a repo ✅ Files, shell, plan out of the box
Research / browsing agent ✅ Deep research, academic, browser subagents
Embed in your product ✅ Library API, no daemon required
One-shot / headless CLI ✅ See fj-ai
Plugin / toolkit author ✅ Depends on nano only
Simple Q&A chat ✅ Strip tools/subagents as needed

Install

uv add soothe-nano

Quick start

from soothe_nano import create_nano_agent
from soothe_nano.config import SootheConfig

agent = create_nano_agent(SootheConfig())
# agent.ainvoke / streaming — see examples/

Library examples live in examples/:

  1. Pure model (no tools)
  2. With tools
  3. With memory
  4. With subagents
  5. Full composition
python packages/soothe-nano/examples/01_pure_nano_example.py

Productive CLI (reference: fj-ai)

fj-ai is a production one-shot coding CLI built only on soothe-nano (no soothe daemon). Use it as the integration blueprint:

pip install fj-ai   # or: uv tool install fj-ai
fj explain this repo
fj -f what did we decide last time?

Integration pattern

A headless CLI typically does four things on top of nano:

  1. Load config~/.soothe/config/nano.yml, or zero-config from OPENAI_API_KEY / ANTHROPIC_API_KEY
  2. Force SQLite for standalone runs (threads survive across process exits)
  3. Build the agent with create_nano_agent, pin workspace, attach a checkpointer
  4. Stream agent.astream(...) and close the aiosqlite connection on exit

Minimal sketch (same shape as fj_ai/agent.py):

from __future__ import annotations

import asyncio
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Any, AsyncIterator

from soothe_nano import SootheNanoAgent, create_nano_agent
from soothe_nano.config import SOOTHE_HOME, SootheConfig
from soothe_nano.resolve import resolve_checkpointer


def load_config(path: Path | None = None) -> SootheConfig:
    cfg = path or (SOOTHE_HOME / "config" / "nano.yml")
    if cfg.is_file():
        return SootheConfig.from_yaml_file(str(cfg))
    return SootheConfig()  # OPENAI_API_KEY / ANTHROPIC_API_KEY


def apply_cli_defaults(config: SootheConfig) -> SootheConfig:
    durability = config.agent.protocols.durability.model_copy(
        update={"backend": "sqlite", "checkpointer": "sqlite"}
    )
    protocols = config.agent.protocols.model_copy(update={"durability": durability})
    agent = config.agent.model_copy(update={"protocols": protocols})
    persistence = config.persistence.model_copy(update={"default_backend": "sqlite"})
    return config.model_copy(update={"agent": agent, "persistence": persistence})


@asynccontextmanager
async def open_sqlite_checkpointer(config: SootheConfig) -> AsyncIterator[Any | None]:
    result = resolve_checkpointer(apply_cli_defaults(config))
    db_path = result[1] if isinstance(result, tuple) and isinstance(result[1], str) else None
    if not db_path:
        yield None
        return

    import aiosqlite
    from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
    from soothe_sdk.utils.serde import create_soothe_serde

    Path(db_path).parent.mkdir(parents=True, exist_ok=True)
    conn = await aiosqlite.connect(db_path)
    checkpointer = AsyncSqliteSaver(conn, serde=create_soothe_serde())
    await checkpointer.setup()
    try:
        yield checkpointer
    finally:
        await conn.close()  # required — aiosqlite uses a non-daemon thread


async def build_agent(
    config: SootheConfig,
    *,
    checkpointer: Any | None = None,
) -> SootheNanoAgent:
    agent = create_nano_agent(apply_cli_defaults(config))
    if checkpointer is not None:
        agent.graph.checkpointer = checkpointer
    return agent


async def run_once(query: str, *, thread_id: str) -> None:
    config = load_config()
    async with open_sqlite_checkpointer(config) as checkpointer:
        agent = await build_agent(config, checkpointer=checkpointer)
        async for chunk in agent.astream(
            query,
            config={"configurable": {"thread_id": thread_id}},
            stream_mode=["messages", "updates", "custom"],
        ):
            # render tokens / tool progress to stdout (see fj_ai/stream.py)
            _ = chunk


if __name__ == "__main__":
    asyncio.run(run_once("summarize this repo", thread_id="cli-demo"))

What fj adds on top of nano

Concern fj-ai approach
UX One-shot fj <query…>; -f / -t resume threads; -l list
Persistence SQLite checkpointer under $SOOTHE_DATA_DIR
Skills Package builtin/ via register_builtin_skill_root
Workspace SOOTHE_WORKSPACE / cwd for file + shell tools
Streaming Quiet progress line + full final answer (stream.py)
Setup fj setup writes ~/.soothe/config/nano.yml

For a full TUI / StrangeLoop host on the same stack, see mirasoth/soothe. For the slim CLI product, clone caesar0301/fj-ai.

Development

From packages/soothe-nano/:

make help              # list targets
make sync             # sync dev deps
make format lint       # format + lint
make test-unit         # unit tests
make test-integration  # integration tests (--run-integration)
make examples          # run examples
make build             # build dist/

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

soothe_nano-1.2.24.tar.gz (1.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

soothe_nano-1.2.24-py3-none-any.whl (1.6 MB view details)

Uploaded Python 3

File details

Details for the file soothe_nano-1.2.24.tar.gz.

File metadata

  • Download URL: soothe_nano-1.2.24.tar.gz
  • Upload date:
  • Size: 1.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for soothe_nano-1.2.24.tar.gz
Algorithm Hash digest
SHA256 723802d1b1a3ff5ff116e999401faf6e80a743ac76c3fe9878c98b612fccd82c
MD5 029546f63fd9bfa6f74f11a61efcf8af
BLAKE2b-256 1adbd74f976386e7be8fd9a267cc48a2333b2d8345544cb346ef577da1b6c23e

See more details on using hashes here.

File details

Details for the file soothe_nano-1.2.24-py3-none-any.whl.

File metadata

  • Download URL: soothe_nano-1.2.24-py3-none-any.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for soothe_nano-1.2.24-py3-none-any.whl
Algorithm Hash digest
SHA256 bb187ad573766ae726671c97fc4aedcef15d7f49951e33c21c18e649fbb24703
MD5 b323fcd73a78d0fd0f696df66519e5b6
BLAKE2b-256 b20d15fb4899041659c900d790651234e0ee9f4dd8f826417687559ea88bf3a6

See more details on using hashes here.

Release history Release notifications | RSS feed

1.2.28

2 files

1.2.27

2 files

1.2.26

2 files

1.2.25

2 files

This release

1.2.24 This release

2 files

1.2.23

2 files

1.2.22

2 files

1.2.21

2 files

1.2.20

2 files

1.2.19

2 files

1.2.18

2 files

1.2.17

2 files

1.2.16

2 files

1.2.15

2 files

1.2.14

2 files

1.2.13

2 files

1.2.12

2 files

1.2.10

2 files

1.2.9

2 files

1.2.8

2 files

1.2.7

2 files

1.2.6

2 files

1.2.5

2 files

1.2.4

2 files

1.2.3

2 files

1.2.2

2 files

1.2.1

2 files

1.2.0

2 files

1.1.19

2 files

1.1.17

2 files

1.1.16

2 files

1.1.15

2 files

1.1.14

2 files

1.1.13

2 files

1.1.12

2 files

1.1.11

2 files

1.1.10

2 files

1.1.9

2 files

1.1.8

2 files

1.1.7

2 files

1.1.6

2 files

1.1.5

2 files

1.1.4

2 files

1.1.2

2 files

1.1.1

2 files

1.1.0

2 files

1.0.15

2 files

1.0.14

2 files

1.0.13

2 files

1.0.12

2 files

1.0.11

2 files

1.0.10

2 files

1.0.8

2 files

1.0.7

2 files

1.0.6

2 files

1.0.5

2 files

1.0.4

2 files

1.0.3

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

0.9.11

2 files

0.9.9

2 files

0.9.8

2 files

0.9.7

2 files

0.9.6

2 files

0.9.5

2 files

0.9.4

2 files

0.9.2

2 files

0.9.1

2 files

0.9.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page