Platform for building interactive agentic applications.
Project description
mashpy
Platform for building CLI-native agent applications.
MashPy is delivered as four offerings that work together: the mash framework runtime, mash-cli for interactive shell UX, mash-api for HTTP/OpenAPI serving, and mash-telemetry-web for optional observer UI assets.
Install
uv add mashpy
Install API server package:
uv add mash-api
# or
uv add "mashpy[api]"
Install CLI package:
uv add mash-cli
# or
uv add "mashpy[cli]"
# validate the CLI installation:
mash --version
Install telemetry observer UI package (optional):
uv add "mashpy[telemetry-web]"
What MashPy Does
MashPy provides four offerings:
mash(frommashpy)- Framework/runtime for agents: orchestration, memory, tools, skills, MCP, and logging.
mash-cli- Interactive shell package (
CLIAppShell, slash commands, REPL) and themashterminal command.
- Interactive shell package (
mash-api- FastAPI/OpenAPI package for serving runtime interaction and observability HTTP endpoints.
mash-telemetry-web- Optional static web UI assets that can be used by API observers.
In interactive usage with mash-cli, each input line follows one of two paths:
- Slash command path:
- local commands (
/help,/exit,/clear) run entirely inmash-cli. - runtime commands (
/session,/prefs,/app_data,/history,/compact) callMashAgentClientcontrol APIs.
- local commands (
- Agent path (normal message):
mash-clisends the message toMashAgentClient, thenMashAgentServerbuilds context, runs the agent loop, executes tools, and persists/logs the turn.
This lets you combine deterministic CLI controls with model-driven tool execution in one interface.
mash-cli (CLIAppShell) owns user interaction. mashpy (MashAgentServer) owns agent execution.
System Architecture
High-level view of how CLI and API users enter the system, how the primary agent can invoke subagents, and how telemetry is captured.
flowchart TB
U1[CLI User]
U2[API User]
subgraph ENTRY[Entry Points]
CLI[CLI Layer]
API[API Layer]
end
subgraph HOST[MashAgentHost]
P[Primary Agent]
S[Subagent]
end
subgraph OBS[Telemetry]
LOG[Event Logger / JSONL]
UI[Observer UI]
end
U1 --> CLI
U2 --> API
CLI --> HOST
API --> HOST
P --> S
P --> OBS
S --> OBS
API --> OBS
LOG --> UI
Agent Runtime
Shared runtime structure used by both the primary agent and any subagent.
flowchart TB
CLIENT[MashAgentClient]
SERVER[MashAgentServer]
LOOP[Agent Loop]
TOOLS[Tools / Skills / MCP / Bash]
STORE[(Memory Store)]
LLM[LLM Provider]
CLIENT --> SERVER
SERVER --> LOOP
LOOP --> TOOLS
LOOP <--> STORE
LOOP <--> LLM
Subagent Invocation Flow
Runtime sequence showing how the primary agent delegates work to a subagent and incorporates the result.
sequenceDiagram
participant User
participant Entry as CLI/API Layer
participant P as Primary Agent
participant S as Subagent
participant T as Telemetry
User->>Entry: Send request
Entry->>P: Start agent run
P->>T: Log run start
P->>P: Reason / use tools
P->>S: Invoke subagent
S->>T: Log subagent run
S-->>P: Return result
P->>T: Log final result
P-->>Entry: Final response
Entry-->>User: Response
Core Modules
This section covers mash framework modules only.
Core (mash.core)
Agent configuration and think/act loop primitives (Agent, provider interfaces, context/response types).
Runtime (mash.runtime)
Host/client/server orchestration for app execution (MashAgentHost, MashAgentClient, MashAgentServer, app definitions).
Memory Store
SQLiteStore persists conversation turns, signals, preferences, and app data. This gives both commands and tools durable state across turns and sessions.
Agent Loop
The agent runs a bounded think/act/observe loop (max_steps) for non-command messages. It builds context from prompt + recent history, calls tools when needed, and writes final response metadata (including token usage).
Skills
Skills are discoverable instructions stored in local SKILL.md files and registered via SkillRegistry. When skills_enabled=True, Mash auto-injects a Skill tool so the model can load skill content at runtime.
Runtime Tools
MashAgentServer auto-registers runtime tools for memory access (enabled by default):
search_conversations- Search conversation history at session or app scope.get_full_turn_message- Fetch full user and assistant messages for one or more turns.get_preferences- read stored user preferences.set_preferences- update stored user preferences.list_app_data- list stored app-scoped key/value entries.set_app_data- persist app-scoped key/value data.
BashTool
BashTool is an opt-in execution tool for shell commands in a persistent bash session. Register it explicitly in your app when you want repository inspection or CLI automation from the agent.
bash- execute shell commands with timeout controls and output truncation safeguards.
Remote MCP Tools
MCPManager manages remote MCP server connections, optional tool allowlists, and tool invocation. Remote MCP tools are adapted into normal Mash tools so the agent can call them like local tools.
Logging Backend (mash.logging)
EventLogger writes structured JSONL events for commands, LLM calls, agent steps, MCP activity, and memory-search stages.
How to Write a New App
Use one MashRuntimeDefinition as the source of truth, then compose it into either a CLI app (mash-cli) or an API app (mash-api).
Quickstart (CLI + API + Telemetry Web)
- Build one
MashRuntimeDefinition(example below in this section). - Run it as a CLI app:
uv run --extra cli python -m examples.simple_app
- Run it as an API app:
uv run --extra api python -m examples.api_app --port 8000
- Start telemetry web against that API:
cd src/mash/telemetry/web
npm run dev
- Open:
- API docs:
http://127.0.0.1:8000/docs - Telemetry UI:
http://127.0.0.1:5173
Minimal api_app.py shape:
from pathlib import Path
from mash_api import MashAPIConfig, run_app
from .app_definition import MyAppDefinition
run_app(
MyAppDefinition(Path(".").resolve()),
config=MashAPIConfig(bind_host="127.0.0.1", bind_port=8000),
)
1) Implement MashRuntimeDefinition
Required methods:
get_app_id()build_store()build_tools()build_skills()build_llm()build_agent_config()get_log_destination()
Optional hooks:
build_mcp_servers()enable_runtime_tools()on_startup(runtime)/on_shutdown(runtime)
Minimal shape:
from pathlib import Path
from mash.core.config import AgentConfig
from mash.core.llm import AnthropicProvider, LLMProvider
from mash.memory.store import MemoryStore, SQLiteStore
from mash.runtime import MashRuntimeDefinition
from mash.skills.registry import SkillRegistry
from mash.tools.registry import ToolRegistry
class MyAppDefinition(MashRuntimeDefinition):
def __init__(self, root: Path) -> None:
self.root = root
def get_app_id(self) -> str:
return "my-app"
def build_store(self) -> MemoryStore:
return SQLiteStore(self.root / ".mash" / "my-app.db")
def build_tools(self) -> ToolRegistry:
return ToolRegistry()
def build_skills(self) -> SkillRegistry:
return SkillRegistry()
def build_llm(self) -> LLMProvider:
return AnthropicProvider(app_id="my-app", api_key="...")
def build_agent_config(self) -> AgentConfig:
return AgentConfig(app_id="my-app", system_prompt="You are helpful.")
def get_log_destination(self) -> Path:
return self.root / ".mash" / "logs" / "my-app.jsonl"
2) CLI app design (mash-cli)
Current pattern:
- Parse args (
--root, app-specific flags). - Build your definition.
- Create shell with
CLIAppShell.from_definition(...). - Optionally register custom slash commands.
shell.run()and alwaysshell.shutdown()infinally.
from mash_cli import CLIAppShell, Command
definition = MyAppDefinition(root)
shell = CLIAppShell.from_definition(definition)
shell.register_command(
Command(name="workspace", help="Show workspace", handler=lambda ctx, _a: ctx.renderer.info(str(root)))
)
try:
shell.run()
finally:
shell.shutdown()
For host-managed subagents, pass subagents=[SubagentRegistration(...)] to CLIAppShell.from_definition(...).
Reference examples:
examples/simple_app.pyexamples/command_app.pyexamples/subagent_app.py
Run:
uv run --extra cli python -m examples.simple_app
uv run --extra cli python -m examples.command_app
uv run --extra cli python -m examples.subagent_app
3) API app design (mash-api)
Current pattern:
- Reuse the same runtime definition.
- Call
run_app(definition, config=MashAPIConfig(...)). - Set
observability_memory_db_path(or CLI--memory-db) if you want/api/v1/telemetry/memory/search.
from mash_api import MashAPIConfig, run_app
run_app(
MyAppDefinition(root),
config=MashAPIConfig(
bind_host="127.0.0.1",
bind_port=8000,
api_key=None,
),
)
Reference example:
examples/api_app.py
Run:
uv run --extra api python -m examples.api_app --port 8000
OpenAPI/docs:
http://127.0.0.1:8000/docshttp://127.0.0.1:8000/openapi.json
4) Telemetry web with API app
Start API first, then web UI:
uv run --extra api python -m examples.api_app --port 8000
cd src/mash/telemetry/web
npm run dev
Open http://127.0.0.1:5173.
The Vite proxy forwards /api/* to http://127.0.0.1:8000.
If model responses should work end-to-end, set ANTHROPIC_API_KEY before running.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mashpy-0.1.4.tar.gz.
File metadata
- Download URL: mashpy-0.1.4.tar.gz
- Upload date:
- Size: 72.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0157d198a9175693d9c0176011949f7cbc7fbd2bc48695765c2ae22cf1390ba
|
|
| MD5 |
d9eefe8e51f10cdb7fbdb075475f7467
|
|
| BLAKE2b-256 |
e0913e34f9cb2321d509d9d97faf0d1790c8566551ba2fea43d5a944c09298da
|
Provenance
The following attestation bundles were made for mashpy-0.1.4.tar.gz:
Publisher:
publish.yml on imsid/mashpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mashpy-0.1.4.tar.gz -
Subject digest:
e0157d198a9175693d9c0176011949f7cbc7fbd2bc48695765c2ae22cf1390ba - Sigstore transparency entry: 1083060946
- Sigstore integration time:
-
Permalink:
imsid/mashpy@31b2d9fde1d10da7c15d873fcda6d693bdc410e9 -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/imsid
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@31b2d9fde1d10da7c15d873fcda6d693bdc410e9 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mashpy-0.1.4-py3-none-any.whl.
File metadata
- Download URL: mashpy-0.1.4-py3-none-any.whl
- Upload date:
- Size: 86.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c603fa39ff50bf6056ed37fbb82204c34c41f8f4a307bb5191eead08714b0a95
|
|
| MD5 |
a68b338219bcd70f780f3bd38cf5c3e9
|
|
| BLAKE2b-256 |
5ef78482f330178e30cdca3e97f03cff09e45777c9fe5b1dad692c93627da74b
|
Provenance
The following attestation bundles were made for mashpy-0.1.4-py3-none-any.whl:
Publisher:
publish.yml on imsid/mashpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mashpy-0.1.4-py3-none-any.whl -
Subject digest:
c603fa39ff50bf6056ed37fbb82204c34c41f8f4a307bb5191eead08714b0a95 - Sigstore transparency entry: 1083061012
- Sigstore integration time:
-
Permalink:
imsid/mashpy@31b2d9fde1d10da7c15d873fcda6d693bdc410e9 -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/imsid
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@31b2d9fde1d10da7c15d873fcda6d693bdc410e9 -
Trigger Event:
release
-
Statement type: