Metadata-Version: 2.4
Name: mahmood-agent
Version: 0.1.1
Summary: Mahmood — a terminal agent, powered by Groq, that operates your machine: shell, files, macOS automation, browser, and HTTP APIs.
Author: Casper White
License: MIT
License-File: LICENSE
Keywords: agent,automation,cli,gpt-oss,groq,llama,llm,terminal
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27
Requires-Dist: keyring>=24.3
Requires-Dist: openai>=1.40
Requires-Dist: prompt-toolkit>=3.0.43
Requires-Dist: rich>=13.7
Requires-Dist: tomli-w>=1.0
Provides-Extra: browser
Requires-Dist: playwright>=1.44; extra == 'browser'
Description-Content-Type: text/markdown

# Mahmood

A terminal agent, powered by Groq, that actually operates your computer — shell,
files, macOS apps, the browser, and the APIs of accounts you own. Fast, because
Groq is.

```bash
pip install mahmood-agent
mahmood setup
mahmood
```

```
› my node build is failing, figure out why and fix it
› what's eating my disk? clean up the safe stuff
› find a 27" 4K monitor under $400, put the best one in my Amazon cart
› open a PR from my current branch with a proper description
› what's on my calendar tomorrow, and text Sam that I'm running late
```

Mahmood reads the situation, runs the commands, and reports what happened. It is
not a chatbot that gives you a list of steps to run yourself.

---

## What it can do

| Area | Tools |
| --- | --- |
| **Shell** | run commands through your login shell, background jobs (dev servers, builds), job output, working directory |
| **Files** | read with line numbers, write with automatic backups, exact-string edits, regex search, glob find, delete to Trash |
| **macOS** | AppleScript/JXA for any app (Mail, Messages, Calendar, Notes, Finder, Music), open apps and URLs, keystrokes via System Events, screenshots it can actually *see*, clipboard, notifications, process control, system report |
| **Browser** | a real visible Chrome window with a persistent profile — navigate, read the page as structured elements, click, type, select, scroll, screenshot, and hand control back to you |
| **Accounts** | authenticated HTTP to GitHub, NVIDIA NGC/NIM, Vercel, Stripe, Linear, Slack, Notion, Cloudflare, OpenAI — plus web search and page fetching |

**Screenshots work even with a text-only model.** `screenshot` and
`browser_screenshot` go to a vision model, whose description is handed back to the
agent — so it can act on what's on screen instead of guessing. If your main model
reads images itself, they're passed through directly and the extra hop is skipped.

---

## Where it stops

This is the part worth reading before you install it.

**Read-only actions just run.** `ls`, `git status`, `grep`, reading a file,
fetching a page — no prompt, no friction.

**Anything that changes something asks first**, with the exact command or diff
shown:

```
╭─ run_command — needs approval ──────────────────╮
│ $ npm install --save-dev vitest                 │
╰─────────────────────────────────────────────────╯
  yes / no / always allow run_command this session / explain first
```

Answer `a` to trust that tool for the rest of the session, or `e` to make
Mahmood explain what it's about to do before you decide.

**Money and one-way doors always ask — even in `--yolo`.** Mahmood will search
for the product, compare options, add it to the cart, fill in shipping and pick
a payment method. Then it stops:

```
╭─ Over to you ───────────────────────────────────╮
│ Dell S2722QC, $379.99. Cart total $379.99 with  │
│ free shipping to 1400 Oak St. Paying with the   │
│ Visa ending 4412. One click left: "Place your   │
│ order".                                         │
│                                                 │
│ https://www.amazon.com/gp/buy/spc/handlers/...  │
╰─ Mahmood is waiting — check it before you click ╯
  press Enter when you're done:
```

The final click is yours. `browser_click` refuses any element whose label
matches the final-commit list — *place order*, *buy now*, *confirm and pay*,
*start membership*, *send money*, *delete account*, and friends. That's a
deliberate limit, not a missing feature: an agent that can spend your money
unattended is one bad inference away from an expensive mistake.

Same for **logins, captchas and 2FA** — Mahmood hands you the browser instead of
typing credentials.

---

## Credentials

**There is no password prompt anywhere in this package.** By design.

- **API tokens** go in your **OS keyring** (macOS Keychain, Secret Service,
  Windows Credential Locker) via `keyring`. Never a plaintext file.
- **Host-pinned.** A token is only ever sent to its own service's hosts. Your
  GitHub token cannot leave `api.github.com`, no matter what a web page says.
- **Site logins** happen in a browser window *you* drive. Mahmood uses a
  dedicated Chrome profile at `~/.config/mahmood/browser-profile`, so you log in
  once and the session persists — and your main Chrome profile is untouched.
- Environment variables (`GROQ_API_KEY`, `GITHUB_TOKEN`, …) are read first if set,
  so CI and direnv setups work without the keyring.

Every account in `mahmood setup` is **optional**. Add none and you still get a
fully working agent with local control; add one and that capability switches on.

---

## Setup

`mahmood setup` walks through six steps, and only the first is required:

1. **Groq API key** — validated against the live API before it's stored. Get one
   at [console.groq.com/keys](https://console.groq.com/keys).
2. **Model** — picked from what your key can actually see, filtered to models that
   can hold a conversation. Defaults to `qwen/qwen3.6-27b`. If you choose a
   text-only model, you're offered a vision model for screenshots.
3. **About you** — one line of context Mahmood gets every session.
4. **Accounts** — the optional tokens above.
5. **Browser control** — installs Playwright and Chromium if you want it.
6. **Approvals** — command prefixes to pre-approve, e.g. `git, npm run`.

Check the result any time:

```bash
mahmood doctor     # what works on this machine, what doesn't
mahmood accounts   # which credentials are configured
mahmood tools      # every tool, with its risk level
```

### Which model

An agent lives or dies by tool calling, not by benchmark scores. These are
results from running the same multi-step task — *run the failing test, fix the
source, re-run to prove it passes* — through Mahmood on Groq:

| Model | Verdict |
| --- | --- |
| `qwen/qwen3.6-27b` | **Default.** Completed the task cleanly first time, and reads images, so screenshots need no second model. |
| `openai/gpt-oss-120b` | Reasons well, but intermittently emits tool arguments Groq rejects as invalid JSON — usually when writing a multi-line file. Mahmood detects this, tells it to use a heredoc instead, and it then finishes. Text-only. |
| `llama-3.3-70b-versatile` | Sometimes packs the arguments into the function *name*, which the API rejects. Mahmood repairs that shape when it can. Text-only. |
| `llama-3.1-8b-instant` | Fast and cheap, fine for simple one-shot jobs. Loses the thread on long tool chains. |

All of them are selectable. The loop retries transient errors with backoff,
retries malformed tool calls with a nudge, and gives up with a clear suggestion
rather than looping forever.

### Rate limits on Groq's free tier

Worth understanding, because it's the main thing you'll notice. Groq meters
**tokens per minute**, and the free tier is tight:

| Model | TPM |
| --- | --- |
| `llama-3.3-70b-versatile` | 12,000 |
| `qwen/qwen3.6-27b`, `openai/gpt-oss-120b` | 8,000 |
| `llama-3.1-8b-instant` | 6,000 |

An agent re-sends the whole conversation *and* every tool definition on each
step, so a ten-step task can spend 30,000 tokens a minute without any single
request being large. Mahmood reads its actual allowance from Groq's response
headers and works inside it:

- trims the conversation to fit before sending
- waits for the window to roll over instead of failing, telling you why:
  `(rate limit: need ~6,023 tokens, 3,106 left this minute — waiting 37s)`
- on a 413, shrinks the request rather than blindly retrying
- scales how much command output it feeds back, so one `ls -R` can't eat a
  whole window

The result is that long tasks get *slow* on the free tier rather than breaking.
If you'd rather they were fast:

- **`/model llama-3.3-70b-versatile`** — 50% more headroom
- **`--no-browser`** — drops 9 tool definitions, ~900 tokens off every request
- **`/clear` between unrelated tasks** — the biggest win, since history is resent every step
- **[Upgrade to Dev Tier](https://console.groq.com/settings/billing)** — removes the ceiling

`/cost` shows your allowance and what's left in the current window.

### macOS permissions

Desktop control needs two grants in **System Settings → Privacy & Security**,
for your *terminal* app:

- **Screen Recording** — for `screenshot`
- **Accessibility** — for `send_keys`

Skip them and everything else still works.

### Browser extra

```bash
pip install 'mahmood-agent[browser]'
playwright install chromium
```

---

## Usage

```bash
mahmood                          # interactive
mahmood run "update my deps and run the tests"
echo "summarise this log" | mahmood
mahmood -m openai/gpt-oss-120b   # different model for one session
mahmood --yolo                   # skip medium-risk prompts (money still asks)
mahmood --no-browser             # local only
```

In the REPL:

| | |
| --- | --- |
| `/tools` | every tool available right now, with risk levels |
| `/accounts` | configured credentials |
| `/setup` | reconfigure without leaving the session |
| `/yolo` | toggle auto-approval |
| `/model <name>` | switch model |
| `/log` | recent actions, with timestamps and risk |
| `/cwd [path]` | show or change the working directory |
| `/cost` | tokens used this session |
| `/clear` | forget the conversation |
| `/exit` | quit |

---

## Configuration

`~/.config/mahmood/config.toml` — plain TOML, edit it freely:

```toml
model = "qwen/qwen3.6-27b"
vision_model = "qwen/qwen3.6-27b"   # describes screenshots; "" disables them
about_me = "Casper. Projects in ~/dev, mostly Next.js and Python. Be terse."
auto_approve = ["git", "npm run", "pytest"]
protected_paths = ["~/.ssh", "~/.aws", "~/.gnupg", "~/Library/Keychains"]
browser = true
browser_channel = "chrome"
max_steps = 40
temperature = 0.2
```

`protected_paths` are refused by every file tool, full stop. `auto_approve`
prefixes skip the confirmation prompt — keep it to things you'd never regret.

An append-only log of every action Mahmood considered, with its risk level and
whether it ran, lands in `~/.config/mahmood/actions.log`.

---

## Prompt injection

Web pages, files, command output and search results reach the model as
*untrusted data*. Mahmood is instructed to ignore instructions found there and
report them to you instead. The host pinning on credentials is the backstop: if
a page talks the model into trying to exfiltrate a token, the request is refused
before it leaves your machine.

This mitigates the risk; it does not eliminate it. An agent with shell access is
exactly as powerful as your shell. Read the prompts before you approve them —
that's what they're for.

---

## Risk levels

| Level | Meaning | Prompts? |
| --- | --- | --- |
| `safe` | reads only | no |
| `low` | local, recoverable change | yes (`a` to trust) |
| `medium` | mutates state outside this machine | yes (`a` to trust) |
| `high` | destructive or hard to reverse | yes, every time |
| `critical` | spends money, or truly irreversible | **always**, even in `--yolo` |

Shell commands are classified by content, not just by tool: `sudo`, `rm -rf`,
`git push --force`, `twine upload` and similar are promoted to `high`
automatically, and a chained command is only as safe as its least safe segment —
so `ls && rm -rf /` is treated as `rm -rf /`.

---

## Requirements

Python 3.11+. macOS for the desktop tools; shell, files, browser and HTTP work
on Linux too.

## License

MIT
