Name | replkit2 JSON |
Version |
0.7.2
JSON |
| download |
home_page | None |
Summary | A minimal Python framework for building stateful REPL applications with ASCII display |
upload_time | 2025-08-10 21:08:33 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.12 |
license | MIT |
keywords |
cli
framework
mcp
repl
stateful
terminal
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# ReplKit2
Flask-style framework for building stateful REPL applications with rich display, MCP integration, and multi-mode deployment.
## ✨ Features
- 🚀 **Multi-mode**: REPL, CLI, MCP server from one codebase
- 🎨 **Rich display**: Tables, trees, boxes, charts, markdown
- 🔌 **MCP ready**: Tools, resources, prompts for Claude/LLMs
- ⚡ **CLI support**: Traditional command-line interface via Typer
- 🎯 **Type safe**: Full type hints, MCP-compatible validation
## 📦 Installation
```bash
# With uv (recommended)
uv add replkit2 # Core library only
uv add "replkit2[all]" # MCP + CLI support
uv add "replkit2[mcp,cli]" # Same as above
uv add "replkit2[examples]" # For running examples
# Or with pip
pip install replkit2
pip install replkit2[all] # MCP + CLI support
pip install replkit2[mcp,cli] # Same as above
pip install replkit2[examples] # For running examples
```
## 🚀 Quick Start
```python
from dataclasses import dataclass, field
from replkit2 import App
@dataclass
class State:
tasks: list = field(default_factory=list)
next_id: int = 1
app = App("todo", State)
@app.command(display="table", headers=["ID", "Task", "Done"])
def list_tasks(state):
"""List all tasks."""
return [{"ID": t["id"], "Task": t["text"], "Done": "✓" if t["done"] else ""}
for t in state.tasks]
@app.command()
def add(state, text: str):
"""Add a task."""
task = {"id": state.next_id, "text": text, "done": False}
state.tasks.append(task)
state.next_id += 1
return f"Added: {text}"
@app.command()
def done(state, id: int):
"""Mark task as done."""
for task in state.tasks:
if task["id"] == id:
task["done"] = True
return f"Completed task {id}"
return f"Task {id} not found"
if __name__ == "__main__":
import sys
if "--mcp" in sys.argv:
app.mcp.run() # MCP server for Claude/LLMs
elif "--cli" in sys.argv:
app.cli() # Traditional CLI
else:
app.run(title="Todo Manager") # Interactive REPL
```
**Run it:**
```bash
python todo.py # Interactive REPL
python todo.py --cli add "Buy milk" # CLI mode
python todo.py --cli list_tasks # CLI mode
python todo.py --mcp # MCP server
```
## 🎨 Display Types
```python
@app.command(display="table", headers=["Name", "Status"])
def show_table(state):
return [{"Name": "Item 1", "Status": "Active"}]
@app.command(display="box", title="Info")
def show_box(state):
return "This is in a box!"
@app.command(display="tree")
def show_tree(state):
return {"root": {"child1": "leaf", "child2": ["item1", "item2"]}}
@app.command(display="progress", show_percentage=True)
def show_progress(state):
return {"value": 7, "total": 10}
```
## 🔌 MCP Integration
```python
# Tool (callable action)
@app.command(fastmcp={"type": "tool"})
def process(state, text: str, count: int = 1):
return f"Processed '{text}' {count} times"
# Resource (readable data at app://get_task/123)
@app.command(fastmcp={"type": "resource"})
def get_task(state, id: int):
return {"id": id, "data": state.tasks.get(id)}
# Prompt template
@app.command(fastmcp={"type": "prompt"})
def brainstorm(state, topic: str = ""):
context = "\n".join(t["text"] for t in state.tasks[:5])
return f"Based on these tasks:\n{context}\n\nBrainstorm about: {topic}"
```
Configure Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"todo": {
"command": "python",
"args": ["/path/to/todo.py", "--mcp"]
}
}
}
```
## ⚡ CLI Support
```python
@app.command(
typer={"name": "ls", "help": "List tasks with filters"}
)
def list_tasks(state, done: bool = False, limit: int = 10):
tasks = [t for t in state.tasks if not done or t.get("done")]
return tasks[:limit]
# Usage:
# python todo.py --cli ls --done --limit 5
# python todo.py --cli add "New task"
# python todo.py --cli done 1
```
## 🎯 Type Safety
```python
# ✅ Good - MCP compatible
def cmd(state,
required: str, # Required param
optional: str = None, # Optional with None
items: List[str] = None, # Typed list
config: Dict[str, int] = None, # Typed dict
):
pass
# ❌ Bad - causes "unknown" in MCP
def cmd(state,
untyped, # Missing annotation
opt: Optional[str] = None, # Don't use Optional
either: Union[str, int] = "", # Don't use Union
):
pass
```
## 📁 Examples
- **[`todo.py`](examples/todo.py)** - Full task manager with persistence
- **[`notes_mcp.py`](examples/notes_mcp.py)** - MCP server with all types
- **[`monitor.py`](examples/monitor.py)** - System monitoring dashboard
- **[`typer_demo.py`](examples/typer_demo.py)** - CLI with JSON state
- **[`markdown_demo.py`](examples/markdown_demo.py)** - Markdown rendering
Run examples:
```bash
cd examples
python todo.py # REPL mode
python notes_mcp.py --mcp # MCP server
python typer_demo.py --cli --help # CLI help
```
## 📚 Documentation
- [CHANGELOG.md](CHANGELOG.md) - Version history
- [ROADMAP.md](ROADMAP.md) - Future plans
- [CLAUDE.md](CLAUDE.md) - Development guide
- [src/replkit2/llms.txt](src/replkit2/llms.txt) - LLM quick reference
## 🛠️ Development
```bash
# Clone and install
git clone https://github.com/angelsen/replkit2
cd replkit2
uv sync --group dev
# Type check
uv run basedpyright src/replkit2
# Format & lint
uv run ruff format src/
uv run ruff check src/
```
## 📄 License
MIT - see [LICENSE](LICENSE) for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "replkit2",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": "cli, framework, mcp, repl, stateful, terminal",
"author": null,
"author_email": "Fredrik Angelsen <fredrikangelsen@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/e9/e5/60854fb976235d18c844c49fc6e89a0e07970c136f0d8600f4b4db87a9cc/replkit2-0.7.2.tar.gz",
"platform": null,
"description": "# ReplKit2\n\nFlask-style framework for building stateful REPL applications with rich display, MCP integration, and multi-mode deployment.\n\n## \u2728 Features\n\n- \ud83d\ude80 **Multi-mode**: REPL, CLI, MCP server from one codebase\n- \ud83c\udfa8 **Rich display**: Tables, trees, boxes, charts, markdown\n- \ud83d\udd0c **MCP ready**: Tools, resources, prompts for Claude/LLMs\n- \u26a1 **CLI support**: Traditional command-line interface via Typer\n- \ud83c\udfaf **Type safe**: Full type hints, MCP-compatible validation\n\n## \ud83d\udce6 Installation\n\n```bash\n# With uv (recommended)\nuv add replkit2 # Core library only\nuv add \"replkit2[all]\" # MCP + CLI support\nuv add \"replkit2[mcp,cli]\" # Same as above\nuv add \"replkit2[examples]\" # For running examples\n\n# Or with pip\npip install replkit2\npip install replkit2[all] # MCP + CLI support\npip install replkit2[mcp,cli] # Same as above\npip install replkit2[examples] # For running examples\n```\n\n## \ud83d\ude80 Quick Start\n\n```python\nfrom dataclasses import dataclass, field\nfrom replkit2 import App\n\n@dataclass\nclass State:\n tasks: list = field(default_factory=list)\n next_id: int = 1\n\napp = App(\"todo\", State)\n\n@app.command(display=\"table\", headers=[\"ID\", \"Task\", \"Done\"])\ndef list_tasks(state):\n \"\"\"List all tasks.\"\"\"\n return [{\"ID\": t[\"id\"], \"Task\": t[\"text\"], \"Done\": \"\u2713\" if t[\"done\"] else \"\"} \n for t in state.tasks]\n\n@app.command()\ndef add(state, text: str):\n \"\"\"Add a task.\"\"\"\n task = {\"id\": state.next_id, \"text\": text, \"done\": False}\n state.tasks.append(task)\n state.next_id += 1\n return f\"Added: {text}\"\n\n@app.command()\ndef done(state, id: int):\n \"\"\"Mark task as done.\"\"\"\n for task in state.tasks:\n if task[\"id\"] == id:\n task[\"done\"] = True\n return f\"Completed task {id}\"\n return f\"Task {id} not found\"\n\nif __name__ == \"__main__\":\n import sys\n if \"--mcp\" in sys.argv:\n app.mcp.run() # MCP server for Claude/LLMs\n elif \"--cli\" in sys.argv:\n app.cli() # Traditional CLI\n else:\n app.run(title=\"Todo Manager\") # Interactive REPL\n```\n\n**Run it:**\n```bash\npython todo.py # Interactive REPL\npython todo.py --cli add \"Buy milk\" # CLI mode\npython todo.py --cli list_tasks # CLI mode\npython todo.py --mcp # MCP server\n```\n\n## \ud83c\udfa8 Display Types\n\n```python\n@app.command(display=\"table\", headers=[\"Name\", \"Status\"])\ndef show_table(state):\n return [{\"Name\": \"Item 1\", \"Status\": \"Active\"}]\n\n@app.command(display=\"box\", title=\"Info\")\ndef show_box(state):\n return \"This is in a box!\"\n\n@app.command(display=\"tree\")\ndef show_tree(state):\n return {\"root\": {\"child1\": \"leaf\", \"child2\": [\"item1\", \"item2\"]}}\n\n@app.command(display=\"progress\", show_percentage=True)\ndef show_progress(state):\n return {\"value\": 7, \"total\": 10}\n```\n\n## \ud83d\udd0c MCP Integration\n\n```python\n# Tool (callable action)\n@app.command(fastmcp={\"type\": \"tool\"})\ndef process(state, text: str, count: int = 1):\n return f\"Processed '{text}' {count} times\"\n\n# Resource (readable data at app://get_task/123)\n@app.command(fastmcp={\"type\": \"resource\"})\ndef get_task(state, id: int):\n return {\"id\": id, \"data\": state.tasks.get(id)}\n\n# Prompt template\n@app.command(fastmcp={\"type\": \"prompt\"})\ndef brainstorm(state, topic: str = \"\"):\n context = \"\\n\".join(t[\"text\"] for t in state.tasks[:5])\n return f\"Based on these tasks:\\n{context}\\n\\nBrainstorm about: {topic}\"\n```\n\nConfigure Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json`):\n```json\n{\n \"mcpServers\": {\n \"todo\": {\n \"command\": \"python\",\n \"args\": [\"/path/to/todo.py\", \"--mcp\"]\n }\n }\n}\n```\n\n## \u26a1 CLI Support\n\n```python\n@app.command(\n typer={\"name\": \"ls\", \"help\": \"List tasks with filters\"}\n)\ndef list_tasks(state, done: bool = False, limit: int = 10):\n tasks = [t for t in state.tasks if not done or t.get(\"done\")]\n return tasks[:limit]\n\n# Usage:\n# python todo.py --cli ls --done --limit 5\n# python todo.py --cli add \"New task\"\n# python todo.py --cli done 1\n```\n\n## \ud83c\udfaf Type Safety\n\n```python\n# \u2705 Good - MCP compatible\ndef cmd(state, \n required: str, # Required param\n optional: str = None, # Optional with None\n items: List[str] = None, # Typed list\n config: Dict[str, int] = None, # Typed dict\n):\n pass\n\n# \u274c Bad - causes \"unknown\" in MCP\ndef cmd(state,\n untyped, # Missing annotation\n opt: Optional[str] = None, # Don't use Optional\n either: Union[str, int] = \"\", # Don't use Union\n):\n pass\n```\n\n## \ud83d\udcc1 Examples\n\n- **[`todo.py`](examples/todo.py)** - Full task manager with persistence\n- **[`notes_mcp.py`](examples/notes_mcp.py)** - MCP server with all types\n- **[`monitor.py`](examples/monitor.py)** - System monitoring dashboard\n- **[`typer_demo.py`](examples/typer_demo.py)** - CLI with JSON state\n- **[`markdown_demo.py`](examples/markdown_demo.py)** - Markdown rendering\n\nRun examples:\n```bash\ncd examples\npython todo.py # REPL mode\npython notes_mcp.py --mcp # MCP server\npython typer_demo.py --cli --help # CLI help\n```\n\n## \ud83d\udcda Documentation\n\n- [CHANGELOG.md](CHANGELOG.md) - Version history\n- [ROADMAP.md](ROADMAP.md) - Future plans \n- [CLAUDE.md](CLAUDE.md) - Development guide\n- [src/replkit2/llms.txt](src/replkit2/llms.txt) - LLM quick reference\n\n## \ud83d\udee0\ufe0f Development\n\n```bash\n# Clone and install\ngit clone https://github.com/angelsen/replkit2\ncd replkit2\nuv sync --group dev\n\n# Type check\nuv run basedpyright src/replkit2\n\n# Format & lint\nuv run ruff format src/\nuv run ruff check src/\n```\n\n## \ud83d\udcc4 License\n\nMIT - see [LICENSE](LICENSE) for details.",
"bugtrack_url": null,
"license": "MIT",
"summary": "A minimal Python framework for building stateful REPL applications with ASCII display",
"version": "0.7.2",
"project_urls": {
"Issues": "https://github.com/angelsen/replkit2/issues",
"Repository": "https://github.com/angelsen/replkit2"
},
"split_keywords": [
"cli",
" framework",
" mcp",
" repl",
" stateful",
" terminal"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "7201984669c164ec4b2fb496c218f1f54765e05f3041cc1addf33a435136742e",
"md5": "615ec877fe29d01f8ac496072cfc3ef7",
"sha256": "8b472c9de6f488016785d0fa275de51b9d95fe292db0d4ba3d6a404108572214"
},
"downloads": -1,
"filename": "replkit2-0.7.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "615ec877fe29d01f8ac496072cfc3ef7",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 34721,
"upload_time": "2025-08-10T21:08:31",
"upload_time_iso_8601": "2025-08-10T21:08:31.858175Z",
"url": "https://files.pythonhosted.org/packages/72/01/984669c164ec4b2fb496c218f1f54765e05f3041cc1addf33a435136742e/replkit2-0.7.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "e9e560854fb976235d18c844c49fc6e89a0e07970c136f0d8600f4b4db87a9cc",
"md5": "597e17f9eadb33b95dc4d7199af8b996",
"sha256": "971b58df19d97fb377e558c56c6a97f8088a78a1e7fdc2e03995b0159cf1d757"
},
"downloads": -1,
"filename": "replkit2-0.7.2.tar.gz",
"has_sig": false,
"md5_digest": "597e17f9eadb33b95dc4d7199af8b996",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 94849,
"upload_time": "2025-08-10T21:08:33",
"upload_time_iso_8601": "2025-08-10T21:08:33.297633Z",
"url": "https://files.pythonhosted.org/packages/e9/e5/60854fb976235d18c844c49fc6e89a0e07970c136f0d8600f4b4db87a9cc/replkit2-0.7.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-10 21:08:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "angelsen",
"github_project": "replkit2",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "replkit2"
}