Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ release:
## cometcli v{{ .Version }}

An agentic SRE terminal for Cosmos SDK and Cosmos-EVM validators — talk to
your machine and nodes the way you use Claude Code; incidents worked through
to the fix, every change and transaction approved by you.
your machine and nodes in plain language; incidents worked through to the
fix, every change and transaction approved by you.

```bash
curl -fsSL https://raw.githubusercontent.com/abhijitkrm/cometcli/main/scripts/install.sh | bash
Expand Down
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div align="center">
<img src="cometcli.jpg" alt="cometcli" width="1200" />
<h1>cometcli</h1>
<p><b>An agentic SRE terminal for Cosmos validators — Claude Code for your nodes</b></p>
<p><b>An agentic SRE terminal for Cosmos validators</b></p>
</div>

<div align="center">
Expand All @@ -24,7 +24,7 @@

<br/>

cometcli is a terminal you talk to, the way you use Claude Code, built for running
cometcli is an AI terminal you talk to in plain language, built for running
[Cosmos SDK](https://github.com/cosmos/cosmos-sdk) and
[Cosmos-EVM](https://github.com/cosmos/evm) validators. Ask *"is anyone jailed?"* or
*"why is my validator missing blocks?"*. It inspects the node, chain and host, works
Expand All @@ -39,8 +39,7 @@ out the cause, proposes the fix, and carries it out once you approve.
- **Operate** — transactions, governance proposals and votes, upgrades, state sync,
service control, security audits
- **Watch** — live dashboard and alerts to Slack, Discord or Telegram
- **Extend** — settings, memory, custom commands, hooks, MCP servers and subagents,
as in Claude Code
- **Extend** — settings, memory, custom commands, hooks, MCP servers and subagents

<p align="center">
<img src="docs/images/cometcli-startup.png" alt="cometcli starting in the terminal: a comet streaking over the COMETCLI wordmark, the welcome box and the prompt" width="820" />
Expand Down Expand Up @@ -113,7 +112,7 @@ cometcli profile add myval \

## The terminal

An inline chat like Claude Code's: answers land in your normal scrollback, and only
An inline chat: answers land in your normal scrollback, and only
the bottom of the screen redraws.

```
Expand Down Expand Up @@ -287,7 +286,7 @@ agent.

- **Tiers** — `observe → diagnose → local-change → on-chain`. Reads run; changes ask;
transactions always ask.
- **Permission rules** — allow / ask / deny in Claude Code syntax
- **Permission rules** — allow / ask / deny patterns
(`bash(docker logs:*)`, `read(./config/**)`, `node.*`); deny beats ask beats allow.
Every shell command is classified first, scripts and `docker exec` included.
- **Consensus keys are radioactive** — `priv_validator_key.json` is never read into
Expand Down
2 changes: 1 addition & 1 deletion docs/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ cometcli runbook run coordinated-upgrade

```bash
cometcli # bare command = chat TUI (when a profile exists)
cometcli ui # chat-first TUI (Claude Code style): streamed answers,
cometcli ui # chat-first TUI: streamed answers,
# /run tools, approval modals with diffs, txs broadcast
# from the chat. Overview/fleet/logs/send panes on tabs
cometcli serve --open # same agent in a local web chat (127.0.0.1 only,
Expand Down
6 changes: 3 additions & 3 deletions docs/EXTENDING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Extending cometcli

Settings, memory, custom commands, hooks, MCP servers and subagents all live in plain
files. The formats follow Claude Code's, so configs written for it mostly carry over.
files, in the settings format common to AI coding agents, so existing configs mostly carry over.

A **project** is the nearest directory above where you start cometcli that holds a
`.cometcli/` folder, a `COMET.md` or a `.git`.
Expand Down Expand Up @@ -124,7 +124,7 @@ Commands run at points in the loop. Events: `PreToolUse`, `PostToolUse`,
```

`matcher` is a case-insensitive regex over tool names (`bash`, `edit`, `node.status`,
`mcp__grafana__.*`; Claude Code's `Bash` works); empty or `*` matches all. Hooks run
`mcp__grafana__.*`; capitalized names like `Bash` work too); empty or `*` matches all. Hooks run
from the project root with `COMETCLI_PROJECT_DIR` (and `CLAUDE_PROJECT_DIR`) set, and
get the event as JSON on stdin:

Expand Down Expand Up @@ -160,7 +160,7 @@ cometcli mcp remove grafana
```

Scopes: `user` (default, `~/.cometcli/settings.json`), `project` (`.mcp.json` — the
same file Claude Code reads), `local` (`.cometcli/settings.local.json`). `${VAR}` and
the standard project MCP file), `local` (`.cometcli/settings.local.json`). `${VAR}` and
`${VAR:-default}` expand in commands, args, env, URLs and headers.

Servers start with each session; their tools are named `mcp__<server>__<tool>` and,
Expand Down
2 changes: 1 addition & 1 deletion internal/agent/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func RunCommand(a *Agent, c *toolkit.Context, reg *toolkit.Registry, line string
if err := needAgent(); err != nil {
return CmdResult{}, err
}
// the current setup, like Claude Code's /status; in node mode also
// the current setup; in node mode also
// a live snapshot of the node (as a background job: never block)
a.loadMemory()
var b strings.Builder
Expand Down
4 changes: 2 additions & 2 deletions internal/agent/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ const (
// Modes lists the approval postures in shift+tab cycling order.
var Modes = []Mode{ModeOps, ModeAcceptEdits, ModeReadOnly, ModeBypass}

// ParseMode accepts ops | readonly | accept-edits | bypass, plus Claude
// Code's names (default, plan, acceptEdits, bypassPermissions).
// ParseMode accepts ops | readonly | accept-edits | bypass, plus the
// common aliases default, plan, acceptEdits and bypassPermissions.
func ParseMode(s string) (Mode, error) {
switch strings.ToLower(strings.TrimSpace(s)) {
case "", "ops", "rw", "default":
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/mcpservers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
)

// mcpScopePath returns the file a scope's servers live in: user settings,
// the project's .mcp.json (shared with Claude Code), or local settings.
// the project's .mcp.json (the standard project MCP file), or local settings.
func mcpScopePath(scope string) (string, error) {
switch scope {
case "user", "":
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
)

// UICmd is the chat-first terminal app: an agent conversation on the front
// pane (Claude Code style) with overview/fleet/logs/send dashboards behind
// pane with overview/fleet/logs/send dashboards behind
// it — all over the same registry and approval gate as the CLI.
func UICmd(reg *toolkit.Registry) *cobra.Command {
var interval int
Expand Down
2 changes: 1 addition & 1 deletion internal/hooks/hooks.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Package hooks runs operator-defined commands at points in the agent
// loop, with Claude Code's contract: the event arrives as JSON on stdin;
// loop, with the common agent-hook contract: the event arrives as JSON on stdin;
// exit 0 passes (stdout may carry JSON decisions or extra context); exit
// 2 blocks, with stderr as the reason; any other exit is a non-blocking
// error shown to the operator.
Expand Down
2 changes: 1 addition & 1 deletion internal/hooks/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestExitCodes(t *testing.T) {
}
out = runner(t, PreToolUse, "Bash", `exit 2`).Run(ctx, Input{Event: PreToolUse, ToolName: "bash"})
if !out.Block {
t.Fatal("matcher should be case-insensitive (Claude Code's Bash)")
t.Fatal("matcher should be case-insensitive (Bash)")
}
}

Expand Down
6 changes: 3 additions & 3 deletions internal/settings/settings.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Package settings discovers and merges cometcli's file-based
// extensibility: settings.json at user, project and local scope, COMET.md
// memory files, custom slash commands, subagent definitions and MCP
// server configs. Formats follow Claude Code's, so its configs carry over.
// server configs, in the settings format common to AI coding agents.
//
// Project-scope hooks and MCP servers execute commands, so they only take
// effect once the project directory is trusted (`cometcli trust`).
Expand All @@ -28,7 +28,7 @@ const (
ScopeLocal Scope = "local" // <root>/.cometcli/settings.local.json
)

// Permissions mirrors Claude Code's permissions block.
// Permissions is the allow/ask/deny permissions block.
type Permissions struct {
Allow []string `json:"allow,omitempty"`
Ask []string `json:"ask,omitempty"`
Expand Down Expand Up @@ -143,7 +143,7 @@ func Load(cwd string) (*Settings, error) {
s.Sources = append(s.Sources, sc.path)
s.apply(f, sc.scope)
}
// a project's .mcp.json (Claude Code's file) adds project servers
// a project's .mcp.json (the standard project MCP file) adds project servers
if s.Root != "" {
var mj struct {
MCPServers map[string]MCPServer `json:"mcpServers"`
Expand Down
8 changes: 4 additions & 4 deletions internal/toolkit/perm.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (d Decision) String() string {
return "default"
}

// Rule is one permission pattern, in Claude Code's syntax:
// Rule is one permission pattern:
//
// bash any shell command
// bash(git status) exactly this command
Expand All @@ -46,7 +46,7 @@ func (d Decision) String() string {
// val.unjail, node.* registry tools by name or prefix
//
// Tool names match case-insensitively, so Bash(...) and WebFetch(...)
// from Claude Code configs work too.
// from other agents' configs work too.
type Rule struct {
Raw string
Tool string // lower-cased; may end in ".*"
Expand All @@ -55,7 +55,7 @@ type Rule struct {

var ruleRe = regexp.MustCompile(`^\s*([A-Za-z_][A-Za-z0-9_.*-]*)\s*(?:\((.*)\))?\s*$`)

// toolAliases maps Claude Code tool names onto ours.
// toolAliases maps common capitalized tool names (Bash, Read…) onto ours.
var toolAliases = map[string]string{"webfetch": "web_fetch", "todowrite": "todo_write", "multiedit": "edit"}

// ParseRule parses one rule string.
Expand Down Expand Up @@ -130,7 +130,7 @@ func expandPattern(p, root string) string {
case strings.HasPrefix(p, "~/"):
home, _ := os.UserHomeDir()
return filepath.Join(home, p[2:])
case strings.HasPrefix(p, "//"): // Claude Code's absolute-path form
case strings.HasPrefix(p, "//"): // absolute-path form
return p[1:]
case filepath.IsAbs(p):
return p
Expand Down
2 changes: 1 addition & 1 deletion internal/tui/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
)

// chatPane is the conversational front-end: a transcript of user prompts,
// assistant text, tool calls, and approvals — Claude Code style. The agent
// assistant text, tool calls, and approvals. The agent
// may be nil (no provider configured); slash commands and /run still work.
type chatPane struct {
agent *agent.Agent
Expand Down
4 changes: 2 additions & 2 deletions internal/tui/chatui/art.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
)

// The startup art: a comet streaking over "COMETCLI" in block letters,
// the way Claude Code greets you with its name. Drawn only when the
// as a startup greeting. Drawn only when the
// terminal is wide enough; colors degrade with the terminal's profile.

// glyphs is the ANSI Shadow figlet font, for the letters we need.
Expand Down Expand Up @@ -79,7 +79,7 @@ func along(stops []rgb, t float64) lipgloss.Color {
var (
// tail: deep violet far behind, through blue and cyan, to white-hot
tailStops = []rgb{hex("#3B2A6B"), hex("#6A4FC9"), hex("#4F8EF7"), hex("#7FE3F5"), hex("#F2FBFF")}
// wordmark: comet gold through Claude-ish orange to violet
// wordmark: comet gold through coral to violet
wordStops = []rgb{hex("#FFD27A"), hex("#F09A5B"), hex("#D97757"), hex("#C2609E"), hex("#8E6BE8")}
headSt = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFF7E0")).Bold(true)
sparkSt = lipgloss.NewStyle().Foreground(lipgloss.Color("#FFD27A"))
Expand Down
12 changes: 6 additions & 6 deletions internal/tui/chatui/chatui.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Package chatui is cometcli's interactive terminal: an inline,
// scrollback-friendly chat in the style of Claude Code. Finished messages
// scrollback-friendly chat. Finished messages
// are printed into the terminal's normal scrollback; only a small live
// region (streaming text, spinner, input, approval dialog, status line)
// is redrawn.
Expand Down Expand Up @@ -690,7 +690,7 @@ func (m *model) onEvent(e agent.Event) tea.Cmd {
}

// flushThinking closes a finished stretch of thinking into a collapsed
// line, the way Claude Code shows it; ctrl+o prints the text.
// line; ctrl+o prints the text.
func (m *model) flushThinking() tea.Cmd {
t := strings.TrimSpace(m.think)
m.think = ""
Expand Down Expand Up @@ -995,7 +995,7 @@ func (m *model) View() string {
if s := strings.TrimSpace(m.live.String()); s != "" {
b.WriteString("\n" + lastLines("⏺ "+strings.TrimLeft(m.markdown(s), "\n "), 16) + "\n")
}
// running tool calls: blinking bullet, like Claude Code
// running tool calls: blinking bullet
blink := "⏺"
if time.Now().UnixMilli()/500%2 == 1 {
blink = " "
Expand Down Expand Up @@ -1273,7 +1273,7 @@ func (m *model) markdown(s string) string {
zero := uint(0)
cfg.Document.Margin = &zero
cfg.Document.BlockPrefix, cfg.Document.BlockSuffix = "", ""
// Claude Code look: "- " bullets, headings as bold text
// "- " bullets, headings as bold text
cfg.Item.BlockPrefix = "- "
// inline code: just a color, no padding or background
codeColor := "#B1B9F9"
Expand Down Expand Up @@ -1311,7 +1311,7 @@ func userLine(s string) string {
return "\n" + strings.Join(lines, "\n")
}

// result indents text under the previous line with Claude Code's ⎿.
// result indents text under the previous line with ⎿.
func result(s string) string {
if strings.TrimSpace(s) == "" {
return ""
Expand Down Expand Up @@ -1431,7 +1431,7 @@ func todoLines(ts []agent.Todo) string {
return strings.Join(out, "\n")
}

// verbs for the spinner, one picked per turn (Claude Code style)
// verbs for the spinner, one picked per turn
var verbs = []string{"Thinking", "Pondering", "Investigating", "Digging", "Checking", "Inspecting", "Crunching",
"Mulling", "Percolating", "Synthesizing", "Ruminating", "Deliberating", "Tinkering", "Sleuthing", "Untangling"}

Expand Down
Loading