Metadata-Version: 2.4
Name: slife
Version: 0.3.3
Summary: Terminal-based AI agent — a function-calling loop with minimum harness
Project-URL: Homepage, https://github.com/juzcn/slife
Project-URL: Repository, https://github.com/juzcn/slife
Author-email: juzcn <zhangjun@cueb.edu.cn>
License: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Terminals
Requires-Python: >=3.13
Requires-Dist: aiohttp>=3.14.1
Requires-Dist: aiosqlite>=0.22.1
Requires-Dist: fastmcp>=2.0.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: jinja2>=3.1.0
Requires-Dist: json5>=0.15.0
Requires-Dist: keyring>=25.0.0
Requires-Dist: keyrings-cryptfile>=1.3.0
Requires-Dist: openai>=1.0.0
Requires-Dist: pillow>=11.0
Requires-Dist: qrcode>=8.0
Requires-Dist: sqlite-vec>=0.1.9
Requires-Dist: textual>=1.0.0
Provides-Extra: embeddings
Requires-Dist: llama-cpp-python; extra == 'embeddings'
Provides-Extra: mqtt
Requires-Dist: paho-mqtt>=2.0.0; extra == 'mqtt'
Description-Content-Type: text/markdown

# Slife

**Terminal-based AI agent** — chat with an LLM that can execute shell commands, read and write files, search the web, call REST APIs, connect to MCP servers, spawn subagents for parallel work, communicate with other Slife instances over MQTT, and remember everything permanently.

```
┌────────────────────────────────────────────────────────────┐
│  Terminal UI (Textual)                                     │
│  ─────────────────────────────────────────────────────────  │
│  Agent Service — LLM + Tools + Loop + MCP + A2A + Inbox   │
│  ┌──────────┬─────────────┬──────────┬──────────────────┐  │
│  │ MCP Tool │ A2A + MQTT  │ Subagent │ Built-in Plugins │  │
│  │  Proxy   │ Mesh        │ Workers  │ ┌────┬────┬────┐ │  │
│  │          │             │          │ │MCP │Mem │WX  │ │  │
│  └──────────┴─────────────┴──────────┴─┴────┴────┴────┘─┘  │
│  Permanent Memory — hybrid search (grep + FTS5 + semantic)  │
└────────────────────────────────────────────────────────────┘
```

## Install

**Zero prerequisites.**  The install script auto-installs Python 3.13 and uv if needed — then installs slife in an isolated environment.  No git, no Node.js, no C++ compiler required.

### Option 1: Install Script (Recommended)

**macOS / Linux / WSL:**

```bash
curl -fsSL https://raw.githubusercontent.com/juzcn/slife/main/install.sh | bash
```

**Windows PowerShell:**

```powershell
powershell -ExecutionPolicy Bypass -Command "irm https://raw.githubusercontent.com/juzcn/slife/main/install.ps1 | iex"
```

The script checks your Python version, installs [uv](https://docs.astral.sh/uv/) if needed, downloads the latest slife, and installs it in an isolated environment.  [Inspect the script](install.sh) before piping if you prefer.

### Option 2: uv tool install (requires git)

```bash
uv tool install git+https://github.com/juzcn/slife.git
```

### Option 3: pipx (requires git)

```bash
pipx install git+https://github.com/juzcn/slife.git
```

### Option 4: Try Before Installing

```bash
uvx --from git+https://github.com/juzcn/slife.git slife
```

No install — downloads, caches, and runs slife in a temporary environment.

After installation, the `slife` and `credstore` commands are available globally:

| Command | Location |
|---------|----------|
| `slife` | `~/.local/bin/slife` |
| `credstore` | `~/.local/bin/credstore` |
| Package files | `~/.local/share/uv/tools/slife/` |
| User data | `~/.slife/` (auto-created on first run) |

### Uninstall

```bash
uv tool uninstall slife
```

User data (config, memory DB, WeChat sessions, credentials backup) lives in `~/.slife/`. In development (when a `slife.json5` exists in the current directory), data stays in the project directory for easy debugging. Delete manually if desired:

```bash
rm -rf ~/.slife                            # all user data (production)
credstore delete DEEPSEEK_API_KEY          # remove a stored secret
credstore list                             # list all stored credentials
```

### Optional Extras

Slife keeps the default install lean.  Add extras when you need them:

| Extra | Package | What it enables |
|-------|---------|-----------------|
| `embeddings` | `llama-cpp-python` | Local GGUF embeddings for semantic memory search (offline, no API cost). Without it, FTS5 keyword search still works. |
| `mqtt` | `paho-mqtt` | A2A agent mesh via MQTT (`--agent <id>`). Without it, subagent spawning still works — only remote-agent discovery needs MQTT. |

```bash
# Install with one or both extras:
uv tool install "slife[embeddings]" --reinstall
uv tool install "slife[mqtt]" --reinstall
uv tool install "slife[embeddings,mqtt]" --reinstall
```

#### Setting Up Local Embeddings

After installing `slife[embeddings]`, download a GGUF model and configure it:

```bash
# 1. Download a GGUF embedding model (BGE-M3, Q4_K_M quantized, ~300 MiB)
curl -LO https://huggingface.co/ChristianAzinn/bge-m3-gguf/resolve/main/bge-m3-Q4_K_M.gguf

# 2. Launch slife and tell the agent to enable it:
slife
# > enable local embeddings with bge-m3-Q4_K_M.gguf
```

The agent calls `memory_set_embedding` which writes the config and reloads the embedder — **no restart needed**.  Verify with:

```bash
slife
# > check embedding status
```

**Windows users**: `llama-cpp-python` needs a pre-built wheel (no C++ compiler required).  The Vulkan variant works on any GPU and falls back to CPU:

```bash
uv tool install "slife[embeddings]" --reinstall
# Then install the platform wheel into the tool's venv:
uv tool run --from slife pip install "llama-cpp-python @ https://github.com/abetlen/llama-cpp-python/releases/download/v0.3.34-vulkan/llama_cpp_python-0.3.34-py3-none-win_amd64.whl"
```

Alternative CUDA wheels: `v0.3.34-cu132`, `v0.3.34-cu125`; AMD: `v0.3.34-hip-radeon`.

#### Setting Up the MQTT Mesh

After installing `slife[mqtt]`, run a [Mosquitto](https://mosquitto.org/) broker and launch with an agent identity:

```bash
# Terminal 1 — start the broker (or use your existing one)
mosquitto -p 1883

# Terminal 2 — launch slife with an agent identity
slife --agent my-agent
```

Configure broker address in `~/.slife/slife.json5` if not using defaults (`localhost:1883`):

```json5
mqtt: {
  broker: { host: "my-broker.local", port: 1883 },
}
```

## Quick Start

Store your API key and launch:

```bash
credstore set-password                # first time only — sets up encrypted backup
credstore set DEEPSEEK_API_KEY        # masked input, no echo
slife
```

The default config (`slife.json5`) ships with pre-configured MCP servers (filesystem, web fetch, DuckDuckGo search).

## How It Works

Slife is a **function-calling loop**. You type a message → the LLM decides what tools to call → Slife executes them and returns results → the LLM responds → repeat.

```
You: "Find all TODO comments and create GitHub issues for them"
  → LLM calls execute_shell("rg TODO")
  → LLM calls github__create_issue(...) for each one
  → LLM: "Created 7 issues. All linked in the description above."
```

## Configuration

Slife uses a **two-layer** configuration model:

| Layer | Storage | What goes here |
|-------|---------|----------------|
| **Secrets** | OS keyring (credstore) | API keys, tokens, passwords — encrypted at OS level |
| **Config** | `~/.slife/slife.json5` → `env:` | `${VAR}` references + non-secret values (EDITOR, LANG, etc.) |

```json5
// slife.json5
env: {
  DEEPSEEK_API_KEY: "${DEEPSEEK_API_KEY}",   // → resolved from keyring at runtime
  EDITOR: "code",                             // → plain value, no secret
}

models: {
  providers: {
    deepseek: {
      base_url: "https://api.deepseek.com",
      api_key: "${DEEPSEEK_API_KEY}",          // ← ${VAR} syntax throughout
      models: [{ model: "deepseek-v4-pro", name: "DeepSeek V4 Pro", reasoning: true }],
    },
  },
},
active_model: "deepseek/deepseek-v4-pro",
```

`${ENV_VAR}` and `${ENV_VAR:-default}` syntax works everywhere — values resolve at runtime via shell → keyring → config.

## Credential Management

Slife ships with **[credstore](credstore/README.md)** — a standalone cross-platform secret manager backed by the OS keyring with AES-encrypted file backup.  It has its own [full documentation](credstore/README.md).

Quick reference:

```bash
credstore set-password                # first-time setup
credstore set DEEPSEEK_API_KEY        # store (masked atomic dual-write)
credstore get DEEPSEEK_API_KEY        # retrieve, masked output
credstore list                        # list all stored keys
credstore status                      # backend status
```

| Command | Description |
|---------|-------------|
| `set-password` | Init cryptfile, set master key |
| `set KEY` | Atomic dual-write (cryptfile → keyring, rolls back on failure) |
| `get KEY` | Retrieve (keyring, masked) |
| `get KEY -p` | Retrieve (dual-query, plaintext) |
| `delete KEY` | Remove from both stores |
| `list` | List all stored keys |
| `reset-keyring` | Restore keyring from cryptfile backup |
| `reset-backup` | Sync keyring → cryptfile |
| `status` | Backend status |

See **[credstore/README.md](credstore/README.md)** for disaster recovery, Python API, and advanced usage.

## Features

### Tools

All tools are unified as OpenAI function definitions — the LLM sees no difference between a native shell command, an MCP tool, or a REST API endpoint.

| Category | Examples | Location |
|----------|----------|----------|
| **Native** | `execute_shell`, `run_python_script`, `get_os_info` | `slife/tools/*.py` |
| **MCP / REST** | `filesystem__read_file`, `fetch__get`, `serper__search` | Via slife-mcp proxy |
| **Skills** | On-demand plugins with `list_skills` / `use_skill` | `skills/` directory |
| **CLI** | Auto-discovered external commands, persisted with `cli_add_tool` | Runtime registration |
| **A2A** | 13 protocol tools — discovery, routing, lifecycle, broadcast | `slife/tools/a2a.py` |

### Memory

Every conversation turn is permanently recorded.  Hybrid search (grep + FTS5 + semantic via vec0) lets the LLM recall past work.  Memory runs as a built-in plugin (`slife/plugins/memory/`) — a separate process so crashes never race with writes.

```
memory_search("ConnectionError")            → exact error trace
memory_search("MCP config", mode="fts5")    → topic search
memory_search("that bug fix", mode="hybrid")→ semantic recall
memory_search(mode="time", since="2026-07") → browse by date
```

Agent isolation via `--agent alice`. Each agent gets its own DB (`<agent_id>.db`) in the data directory. Embedding via local GGUF (offline) or OpenAI-compatible API.  See [DESIGN.md § Permanent Memory](DESIGN.md#permanent-memory-slife-memory) for the full architecture.

### Plugins

Three built-in plugins ship with Slife, all using the same MCP stdio protocol:

| Plugin | Role |
|--------|------|
| **slife-mcp** | Proxy for external MCP servers (stdio + HTTP) — 10 management tools |
| **slife-memory** | Diary database with hybrid search (FTS5 + vec0 RRF) |
| **slife-wechat** | Bidirectional WeChat messaging via iLink ClawBot API |

**Third-party plugins** are standard MCP servers configured in `slife.json5` →
`mcp.servers`. They auto-connect on startup and their tools are discovered and
registered automatically. Any MCP-compatible server — in Python, Node.js, Go,
Rust, or any other language — works as a Slife plugin.

```json5
// Example: add a custom MCP server
mcp: {
  servers: {
    "my-plugin": {
      command: "uv", args: ["run", "python", "-m", "my_plugin.server"],
      env: { API_KEY: "${API_KEY}" },
      description: "My custom MCP server."
    },
  },
}
```

See [DESIGN.md § Third-Party Plugins](DESIGN.md#third-party-plugins) for the full plugin contract and configuration reference.

### A2A — Agent-to-Agent

Two transports, one interface: **MQTT** (remote peers, enable with `--agent <id>`) and **Subagent** (local child processes, always available).  The unified inbox serializes human keyboard, WeChat, MQTT, and subagent messages through a single queue — only one AgentLoop runs at a time.

### Progressive Disclosure

Not all tools are in every LLM request.  Three categories use lightweight summaries first:

| Category | Browse | Load |
|----------|--------|------|
| Memory | `memory_search` / `memory_list_recent` | `memory_open` |
| Skills | `list_skills` | `use_skill` |
| MCP | `mcp_list_servers` / `mcp_list_tools` | `mcp_set_disclosure("eager")` |

## Shortcuts

| Key | Action |
|-----|--------|
| `Ctrl+C` (in input) | Quit |
| `Ctrl+C` (elsewhere) | Copy (terminal-native) |
| `Esc` | Cancel agent loop |
| `Ctrl+L` | Focus input field |
| `Home` / `End` | Scroll to top / bottom |
| Any key | Auto-focus input + type |

## CLI Flags

| Flag | Default | Description |
|------|---------|-------------|
| `--agent <id>` | `slife` | Agent identity — memory isolation key & A2A mesh identity |

## Requirements

The install script handles everything automatically.  Nothing to install beforehand.

| Component | Status |
|-----------|--------|
| Python ≥ 3.13 | Auto-installed via uv if missing |
| [uv](https://docs.astral.sh/uv/) | Auto-installed if missing |
| Node.js | Optional — only for npx-based MCP servers |
| `llama-cpp-python` | Optional — `slife[embeddings]` for local GGUF embeddings |
| `paho-mqtt` | Optional — `slife[mqtt]` for A2A MQTT mesh |

## Development

Dev mode is detected via `pyproject.toml` — when `[project] name == "slife"`, data files stay in the project directory for easy debugging. Production installs use `~/.slife/`.

```bash
git clone https://github.com/juzcn/slife.git
cd slife
uv sync
uv run slife                      # uses ./slife.json5, data stays in ./
```

For all optional dependencies (embeddings + MQTT):

```bash
uv sync --all-extras
```

Run tests:

```bash
uv run pytest
```

## Design

Slife is a **minimum-harness agent**.  The harness only does what the LLM physically cannot: execute tools, maintain conversation state, stream responses, and persist memory.  Everything else — reasoning, planning, tool selection, error recovery — is the LLM's job.

See [DESIGN.md](DESIGN.md) for the full architecture, component-level documentation, and design rationale.

## License

MIT
