
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
replkit2
Advanced tools
Flask-style framework for building stateful REPL applications with rich display, MCP integration, and multi-mode deployment.
# 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
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:
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
@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}
@app.command(display="markdown")
def show_markdown(state):
return {
"elements": [
{"type": "heading", "content": "Status Report"},
{"type": "alert", "content": "System is operational", "level": "success"},
{"type": "table", "headers": ["Task", "Status"],
"rows": [{"Task": "Backup", "Status": "Complete"}]},
]
}
# 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):
{
"mcpServers": {
"todo": {
"command": "python",
"args": ["/path/to/todo.py", "--mcp"]
}
}
}
@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
Write once, deploy everywhere - REPL, CLI, MCP server, or programmatic API:
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="My App") # Interactive REPL
Integration properties: app.mcp (MCP server), app.cli (CLI), app.state (direct access), app.execute() (programmatic)
See docs/integrations.md for complete integration patterns and web framework examples.
Commands can detect execution mode (REPL, MCP, CLI, programmatic) and adapt behavior accordingly:
from replkit2.types import ExecutionContext
@app.command(display="table", fastmcp={"type": "tool"})
def preview(state, file: str, limit: int = None, _ctx: ExecutionContext = None):
"""Preview with smart defaults based on execution mode."""
if limit is None:
limit = 5 if _ctx and _ctx.is_repl() else None # Compact for REPL, full for MCP/CLI
return load_file(state, file)[:limit] if limit else load_file(state, file)
When to use: Commands with large datasets or different output needs per mode. Key features: Opt-in, auto-injected, backward compatible, user override.
See docs/integrations.md for complete guide.
# ✅ 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
todo.py - Full task manager with persistencenotes.py - Note-taking with MCP integrationdataset.py - Context-aware commandsmonitor.py - System monitoring dashboardtasks.py - CLI with JSON statetodo_api.py - FastAPI integrationRun examples:
cd examples
python todo.py # REPL mode
python dataset.py # Context-aware demo
python notes.py --mcp # MCP server
python tasks.py --cli --help # CLI help
# 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/
MIT - see LICENSE for details.
FAQs
A minimal Python framework for building stateful REPL applications with ASCII display
We found that replkit2 demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.