Help us shape the future of Go! Take the 2026 Go Developer Survey

hmm

command module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 6 Imported by: 0

README ΒΆ

🫀 hmm

hmm (interj.) β€” what you type right before you ask.

CI Version

The first agent built on weft: one fast Go binary for quick-asking from the CLI β€” hmm "question", pipes in, streamed answers out β€” that can also create its own tools at runtime as sandboxed subprocess plugins and register them without rebuilding.

Why "hmm"?

Because it's the shortest honest name for what this is: the sound of a question forming. You're mid-thought in the terminal, something looks off, and hmm is literally what you mutter β€” so the command is the interjection: hmm "is this diff right?". Three keys, no subcommand, no ceremony β€” a question should cost less than the answer.

The project was born as bobina (the bobbin that feeds the weft β€” the weaving metaphor), then renamed: the command is what you type all day, so it got the three keys. The pre-rename BOBINA_* env vars and ~/.local/share/bobina tree still work (picked up automatically), and Wefty stays the mascot.

Status: v0.1.0 β€” one-shot ask, piped stdin, four core tools, sessions with -c resume, --json, conversation mode (interactive chat / stdin-line loop), and the plugin library (the agent writes and mounts its own tools mid-run, on weft v0.1.0's RawTool/ToolSource). All offline-tested (make test).

Run it

Install (Go 1.26+):

go install github.com/weftgo/hmm@v0.1.0
hmm --version             # hmm 0.1.0

Or build from source:

git clone https://github.com/weftgo/hmm
cd hmm && go build -o hmm .

Set it once β€” then just ask

hmm config init writes a template config; put your provider, model, and key in it and never type them again:

./hmm config init
$EDITOR ~/.config/hmm/config.toml
provider = "kimi"
kimi_model = "kimi-k2.6"    # models are per provider β€” they never leak across
kimi_key = "sk-..."         # account also offers kimi-k3, kimi-k2.7-code[-highspeed]
# zai_model = "glm-5.3-flash"   # optional: zai's default when unset
# zai_key = "..."
./hmm "say hi"          # no flags, no env vars
./hmm config            # shows what resolves from where (keys are never printed)

Precedence when several sources disagree: flag > env > config file > defaults. The file holds keys, so config init writes it 0600 β€” keep it that way.

See and pick models β€” hmm models lists what your account actually offers (fetched live, current default marked), and lets you choose:

./hmm models                 # lists the resolved provider's models
./hmm models --provider zai  # any provider
./hmm models --set kimi-k3   # persist the choice into the config
./hmm models                 # on a TTY: pick by number instead
./hmm --model kimi-k3 "hi"   # one run only, config untouched

Pick a provider (env key), then ask. --provider defaults to anthropic; zai is z.ai's GLM over their OpenAI-compatible endpoint.

# z.ai GLM β€” the quickest start
export HMM_ZAI_KEY='your-zai-key'      # or ZAI_API_KEY
./hmm --provider zai "say hi"          # glm-5.3-flash by default
./hmm --provider zai --model glm-5.3 "explain this channel semantics"

# Kimi (Moonshot) β€” OpenAI-compatible endpoint
export HMM_KIMI_KEY='your-kimi-key'    # or KIMI_API_KEY / MOONSHOT_API_KEY
./hmm --provider kimi "say hi"         # kimi-k2.6 by default

# Anthropic (default provider)
export ANTHROPIC_API_KEY='sk-...'
./hmm --model <model-id> "review this design"

# OpenAI, or any OpenAI-compatible gateway via OPENAI_BASE_URL
export OPENAI_API_KEY='sk-...'
./hmm --provider openai --model <model-id> "hi"

# Google
export GEMINI_API_KEY='...'
./hmm --provider google --model <model-id> "hi"

anthropic/openai/google have no built-in model default β€” pass --model or set HMM_MODEL. (HMM_PROVIDER also works as the provider fallback.)

Pipes are first-class β€” stdin is fenced into the prompt, capped at 64 KiB, and nothing ever blocks waiting for input:

git diff | ./hmm --provider zai "review this diff"
./hmm --provider zai "summarize" < notes.txt
dmesg | ./hmm --provider zai --yolo "what driver is failing?"   # --yolo enables run_command

Continue a conversation (every run is saved under ~/.local/share/hmm/sessions/):

./hmm -c "and what about error handling?"   # one-shot follow-up
./hmm --resume <id-prefix> "pick up where we left off"
./hmm -c                                    # …or keep chatting: interactive

Every one-shot ends with a hint (↻ hmm -c "follow-up" Β· hmm -c β€” continue this chat). With no prompt at all, hmm is a conversation: on a terminal it's an interactive chat β€” banner, β€Ί prompt, streamed answers, /exit or Ctrl-D to leave, Ctrl-C saves and exits β€” and a pipe drives the same loop, one prompt per line (echo "hi" | ./hmm). -c continues the last session from the current directory (each terminal its own thread); session ids are human-readable (amber-moth-482), and --resume accepts a unique prefix.

On a terminal, hmm runs its Charm layer (lipgloss + glamour + bubbles): the answer renders as markdown (theme follows your terminal's dark/light background; GLAMOUR_STYLE overrides), a spinner carries the live status (thinking Β· latest reasoning, βš™ tool calls, step finishes), and the activity feed is color-themed. Piped output stays byte-clean β€” raw markdown, plain feed, no spinner β€” so hmm "q" > file.md and | jq keep working. --quiet hides the narration on a TTY too.

Machine output β€” one weft event per line (the weft wire contract):

./hmm --json --provider zai "hi" | jq -s 'map(.type)'

Flags: --provider --model --system --max-steps --sequential --yolo --json --quiet --resume <id|prefix|path> -c --version

Exit codes: 0 ok Β· 1 run error Β· 2 usage Β· 130 interrupted (partial transcript still saved)

Safety stance: run_command requires a TTY y/N confirm, or --yolo to skip it; a piped run without --yolo refuses and tells the model why. Be clear about what that is: the y/N gates (and the --trust workspace gate) are policy and UX, not a security boundary β€” a compromised prompt can still try to talk its way past a human. The actual boundary is structural: model-written code runs as a subprocess with a timeout, never in-process; every plugin passes a selftest before it enters the library; and OS-level sandboxing is planned next. Don't run --yolo in a repo you don't trust.

The plugin library (the signature feature)

The agent can create its own tools mid-conversation and call them by name in the very next step β€” no rebuild, no restart (this rides two seams hmm drove into weft: RawTool and ToolSource):

./hmm --provider zai --yolo "you need a tool that base64-encodes its input β€” write it, install it, and prove it works"
./hmm -c "now encode 'hello weft'"        # the tool persists across runs

Plugins live in ~/.local/share/hmm/plugins/<name>/ β€” a plugin.json manifest plus source (go compiles at install; sh and python run verbatim). Every install is confirmation-gated (the TTY y/N prompt shows the plugin's code β€” approve what will actually run β€” or --yolo to skip), every plugin must pass its selftest before entering the library, and plugin code runs as a subprocess with a per-call timeout: args as JSON on stdin, stdout as the tool result.

Built on weft as its first real consumer; mascot: Wefty.

License

MIT β€” see LICENSE.

Documentation ΒΆ

Overview ΒΆ

Command hmm is a quick-ask agent for the command line, built on weft. main only wires the OS streams and signals; the CLI itself lives in internal/cli.

Directories ΒΆ

Path Synopsis
internal
agent
Package agent resolves provider configuration into a weft.Model and assembles the hmm agent: name, system prompt, core tools, loop policy.
Package agent resolves provider configuration into a weft.Model and assembles the hmm agent: name, system prompt, core tools, loop policy.
cli
Package cli is hmm's command line: flag parsing, stdin handling, the turn pump, session persistence, and exit codes.
Package cli is hmm's command line: flag parsing, stdin handling, the turn pump, session persistence, and exit codes.
config
Package config loads hmm's set-it-once configuration file β€” provider, model, and provider keys, so a plain `hmm "question"` needs no flags and no env vars.
Package config loads hmm's set-it-once configuration file β€” provider, model, and provider keys, so a plain `hmm "question"` needs no flags and no env vars.
models
Package models lists the models a provider account actually offers β€” `hmm models`.
Package models lists the models a provider account actually offers β€” `hmm models`.
plugins
Package plugins is hmm's tool library: model-written tools live as subprocesses behind a manifest, are mounted as first-class weft tools via weft.RawTool, and β€” thanks to weft.ToolSource β€” a plugin installed mid-run is callable by name in the next step.
Package plugins is hmm's tool library: model-written tools live as subprocesses behind a manifest, are mounted as first-class weft tools via weft.RawTool, and β€” thanks to weft.ToolSource β€” a plugin installed mid-run is callable by name in the next step.
procs
Package procs configures subprocess execution so that cancelling a command's context actually bounds the call.
Package procs configures subprocess execution so that cancelling a command's context actually bounds the call.
session
Package session persists every hmm run as a JSONL file in weft's message wire format: line 1 is a session header, then one weft Message per line, then a final usage line.
Package session persists every hmm run as a JSONL file in weft's message wire format: line 1 is a session header, then one weft Message per line, then a final usage line.
textutil
Package textutil trims byte-capped output back to UTF-8 rune boundaries.
Package textutil trims byte-capped output back to UTF-8 rune boundaries.
tools
Package tools defines hmm's core tools: read_file, list_dir, grep, and run_command.
Package tools defines hmm's core tools: read_file, list_dir, grep, and run_command.
ui
Package ui is hmm's Charm layer β€” every terminal write in the binary goes through it (the rule crush gives its TUI, scaled to an enriched CLI):
Package ui is hmm's Charm layer β€” every terminal write in the binary goes through it (the rule crush gives its TUI, scaled to an enriched CLI):

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL