Skip to content

Commit 24c5d4e

Browse files
committed
chore: initial file addition
1 parent eadf8a3 commit 24c5d4e

30 files changed

+2475
-4
lines changed

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,9 @@ cython_debug/
182182
.abstra/
183183

184184
# Visual Studio Code
185-
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
185+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
186186
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
187-
# and can be added to the global gitignore or merged into this file. However, if you prefer,
187+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
188188
# you could uncomment the following to ignore the entire vscode folder
189189
# .vscode/
190190

@@ -200,6 +200,7 @@ cython_debug/
200200
# refer to https://docs.cursor.com/context/ignore-files
201201
.cursorignore
202202
.cursorindexingignore
203+
.claude
203204

204205
# Marimo
205206
marimo/_static/

.pre-commit-config.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
repos:
2+
- repo: https://github.com/astral-sh/ruff-pre-commit
3+
rev: v0.8.4
4+
hooks:
5+
- id: ruff
6+
args: [--fix]
7+
- id: ruff-format
8+
9+
- repo: https://github.com/pre-commit/mirrors-mypy
10+
rev: v1.13.0
11+
hooks:
12+
- id: mypy
13+
stages: [pre-push]
14+
additional_dependencies: [textual, claude-agent-sdk, pydantic, types-PyYAML]

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.14

.vscode/settings.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"editor.rulers": [88],
3+
"editor.tabSize": 4,
4+
"editor.insertSpaces": true,
5+
"files.exclude": {
6+
"**/.mypy_cache": true,
7+
"**/.ruff_cache": true,
8+
"**/.venv": true,
9+
"**/__pycache__": true,
10+
"**/agent_chat_cli.egg-info": true,
11+
},
12+
"mypy.dmypyExecutable": "${workspaceFolder}/.venv/bin/dmypy",
13+
"mypy.runUsingActiveInterpreter": true,
14+
"ruff.enable": true,
15+
"ruff.lint.enable": true,
16+
"python.analysis.autoImportCompletions": true,
17+
"python.analysis.typeCheckingMode": "basic",
18+
"python.analysis.inlayHints.functionReturnTypes": false,
19+
"python.analysis.inlayHints.variableTypes": false,
20+
21+
"[python]": {
22+
"editor.defaultFormatter": "charliermarsh.ruff",
23+
"editor.formatOnSave": true,
24+
"editor.codeActionsOnSave": {
25+
"source.fixAll.ruff": "always",
26+
"ruff.lint.run": "always"
27+
}
28+
},
29+
"[json,yaml,markdown]": {
30+
"editor.defaultFormatter": "esbenp.prettier-vscode",
31+
"editor.formatOnSave": true
32+
},
33+
}

CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# CLAUDE.md System Settings
2+
3+
## Rules
4+
5+
- The project uses `uv`, `ruff` and `mypy`
6+
- Run commands should be prefixed with `uv`: `uv run ...`
7+
- Use `asyncio` features, if such is needed

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,21 @@
1-
# agent-chat-cli-python
2-
Agent Chat CLI, but in Python
1+
# Agent Chat CLI
2+
3+
This is a less feature-rich Python version of [agent-chat-cli](https://github.com/damassi/agent-chat-cli), which uses the [claude-agent-sdk](https://github.com/anthropics/claude-agent-sdk-python) under the hood. Terminal UI is built on top of the very impressive [Textual](https://textual.textualize.io/).
4+
5+
https://github.com/user-attachments/assets/66a1d462-e51a-419f-80f3-fa69ee60db9c
6+
7+
## Purpose
8+
9+
This tool is for those who wish for slightly more control over their MCP servers via configurable system prompts, and a minimal terminal-based MCP form factor. (It can do a lot of things thanks to the Claude Agent SDK, but the main purpose, at least for me, is a simple, humble and performant MCP interface to whatever tools I typically use day-to-day.)
10+
11+
> Note: The Python version is visually sturdier than the Node.js version. No more crazy terminal flashing like in claude-code!
12+
13+
## Setup
14+
15+
This app uses [uv](https://github.com/astral-sh/uv) for package management so first install that. Then:
16+
17+
- `git clone https://github.com/damassi/agent-chat-cli-python.git`
18+
- `uv sync`
19+
- `uv run chat`
20+
21+
Additional MCP servers are configured in `agent-chat-cli.config.yaml` and prompts added within the `prompts` folder.

agent-chat-cli.config.yaml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Agent Chat CLI Configuration
2+
3+
# System prompt loaded from file
4+
system_prompt: system.md
5+
6+
# Model to use (e.g., sonnet, opus, haiku)
7+
model: sonnet
8+
9+
# Enable streaming responses
10+
include_partial_messages: true
11+
12+
# Named agents with custom configurations
13+
# agents:
14+
# sample_agent:
15+
# description: "Example agent for demonstration"
16+
# prompt: "You are a helpful assistant named Foo."
17+
# mcp_servers:
18+
# - chrome
19+
# - github
20+
# disallowed_tools: []
21+
22+
# MCP server configurations
23+
mcp_servers:
24+
chrome:
25+
description: "Browser automation and debugging capabilities for AI agents"
26+
command: "bunx"
27+
args:
28+
- "chrome-devtools-mcp@latest"
29+
disallowed_tools: []
30+
enabled: true
31+
32+
github:
33+
description: "Search remote code, PRs, issues; discover documentation and deployment guides"
34+
prompt: "github.md"
35+
command: "bunx"
36+
args:
37+
38+
- "https://api.githubcopilot.com/mcp/readonly"
39+
- "--header"
40+
- "Authorization: Bearer ${GITHUB_ACCESS_TOKEN}"
41+
disallowed_tools: []
42+
enabled: true
43+
44+
notion:
45+
description: "Access workspace documentation, wikis, OKRs, and onboarding guides with hierarchical navigation"
46+
command: "bunx"
47+
args:
48+
49+
- "https://mcp.notion.com/mcp"
50+
disallowed_tools: []
51+
enabled: false
52+
53+
# Global tool restrictions
54+
disallowed_tools: []
55+
56+
# Permission mode for tool execution
57+
permission_mode: "bypassPermissions"

pyproject.toml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[project]
2+
name = "agent_chat_cli"
3+
version = "0.1.0"
4+
description = "Add your description here"
5+
readme = "README.md"
6+
requires-python = ">=3.14"
7+
dependencies = [
8+
"asyncio>=4.0.0",
9+
"claude-agent-sdk>=0.1.10",
10+
"mypy>=1.19.0",
11+
"pydantic>=2.12.5",
12+
"python-dotenv>=1.2.1",
13+
"pyyaml>=6.0.3",
14+
"rich>=14.2.0",
15+
"textual[syntax]>=6.7.0",
16+
]
17+
18+
[dependency-groups]
19+
dev = [
20+
"mypy>=1.19.0",
21+
"pre-commit>=4.3.0",
22+
"ruff>=0.14.7",
23+
"textual-dev>=1.8.0",
24+
"types-pyyaml>=6.0.12.20250915",
25+
]
26+
27+
[project.scripts]
28+
chat = "agent_chat_cli.app:main"
29+
dev = "textual_dev.cli:run"
30+
31+
[tool.uv]
32+
package = true

src/agent_chat_cli/__init__.py

Whitespace-only changes.

src/agent_chat_cli/app.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import asyncio
2+
from textual.app import App, ComposeResult
3+
from textual.containers import VerticalScroll
4+
from textual.binding import Binding
5+
6+
from agent_chat_cli.components.header import Header
7+
from agent_chat_cli.components.chat_history import ChatHistory, MessagePosted
8+
from agent_chat_cli.components.thinking_indicator import ThinkingIndicator
9+
from agent_chat_cli.components.user_input import UserInput
10+
from agent_chat_cli.utils import AgentLoop
11+
from agent_chat_cli.utils.message_bus import MessageBus
12+
13+
from dotenv import load_dotenv
14+
15+
load_dotenv()
16+
17+
18+
class AgentChatCLIApp(App):
19+
CSS_PATH = "utils/styles.tcss"
20+
21+
BINDINGS = [Binding("ctrl+c", "quit", "Quit", show=False, priority=True)]
22+
23+
def __init__(self) -> None:
24+
super().__init__()
25+
26+
self.message_bus = MessageBus(self)
27+
28+
self.agent_loop = AgentLoop(
29+
on_message=self.message_bus.handle_agent_message,
30+
)
31+
32+
def compose(self) -> ComposeResult:
33+
with VerticalScroll(id="container"):
34+
yield Header()
35+
yield ChatHistory()
36+
yield ThinkingIndicator()
37+
yield UserInput(query=self.agent_loop.query)
38+
39+
async def on_mount(self) -> None:
40+
asyncio.create_task(self.agent_loop.start())
41+
42+
async def on_message_posted(self, event: MessagePosted) -> None:
43+
await self.message_bus.on_message_posted(event)
44+
45+
46+
def main():
47+
app = AgentChatCLIApp()
48+
app.run()
49+
50+
51+
if __name__ == "__main__":
52+
main()

0 commit comments

Comments
 (0)