Charmant.AI: A Local Agent Experiment in Safe Tool Use

Charmant.AI is an open-source AI layer for local tools, scripts, and repeatable workflows. It is a terminal-based agent that runs on your own machine, reads context about your OS, shell, and project, and calls a small set of built-in tools — files, shell commands, logs, and system inspection — to get real work done.

The project is also an architecture experiment: what should happen before an AI agent can touch the local machine? Every write or execute action is gated by an explicit, configurable permission model, so autonomy is a decision rather than an accident.

The project is open source under the MIT license: github.com/ilich/charmant.ai.

Why I built it

Most AI-agent demos focus on capability: can the agent read files, run commands, edit code, inspect logs, and automate workflows? Charmant.AI explores the harder production question: under what conditions should an agent be allowed to do those things?

Unlike hosted coding assistants, Charmant.AI is designed as a general-purpose local operator: checking disk space, tailing logs, inspecting processes, editing files, and running shell commands from one conversational interface. That makes it useful as a tool, but it also makes the safety model visible. The agent is close to real system state, so permission boundaries, review points, and auditability have to be part of the design.

Charmant.AI treats tool use as an architecture problem, not just a prompting problem. The model can ask to use a tool; a separate permission layer decides whether that request is allowed, denied, or sent to the human for approval.

What it demonstrates

Charmant.AI is intentionally small, but it exercises several design questions that matter in production agent systems:

  • Autonomy needs policy outside the model — the model can request tool calls, but permission modes decide what actually runs.
  • Shell access needs a separate risk boundaryrun_command is dynamically classified as read-only or mutating before execution.
  • Context should be reusable — skills and AGENTS.md turn repeated project knowledge into explicit operating instructions.
  • Audit logs should be designed in from the start — tool selections, approvals, denials, execution results, and mode changes are recorded as structured events.
  • Full automation should be a conscious mode, not the defaultfull-auto exists, but the default posture keeps the human in the loop.

How the permission model works

Every tool call passes two independent checks before it runs: a static risk level on the tool itself (READ, WRITE, or EXECUTE), and the currently active permission mode, which maps each level to allow, confirm, or deny.

ModeREADWRITEEXECUTE
plandenydenydeny
suggestallowdenydeny
auto-editconfirmconfirmconfirm
defaultconfirmconfirmconfirm
full-autoallowallowallow

Shell commands get an extra layer because the same tool can run something harmless, like ls -la, or something destructive, like rm -rf ./build. Before run_command reaches the permission check, a lightweight model classifies the exact command as READ or WRITE. Optional executable allow-lists or deny-lists can block specific programs outright, regardless of permission mode.

This separation matters. The model is not responsible for policing itself. It requests action; the runtime enforces the boundary.

Skills, context, and repeatable workflows

A skill is a reusable prompt saved as a SKILL.md file under .charmant/skills/ (project-scoped) or ~/.charmant/skills/ (available everywhere), with optional YAML frontmatter for a name and description. Skills run as /skill-name in the TUI or charmant run /skill-name from the CLI, and are subject to the same permission mode as any other instruction.

For standing project context — coding conventions, safe commands, deployment quirks — drop an AGENTS.md file at the project root (or under .charmant/ or your home directory) and Charmant.AI appends it to the agent's system instructions automatically.

This is the part of the project that connects most directly to AI-native engineering practice. Useful agents do not only need tools; they need durable context, repeatable instructions, and a controlled way to act on both.

Built-in tools

Charmant.AI ships tools across four categories:

  • File and directory operations — list, read, create, edit, copy, move, and remove files or directories.
  • Shell commands — check command availability or run shell commands through the permission model.
  • Log and text search — tail files, grep text, search logs, extract errors, and parse structured files.
  • System inspection — inspect disk, memory, CPU, network, processes, ports, and environment variables.

New tools are added by decorating a plain Python function with @tool(category, risk_level=...); there is no separate registry to maintain. Run uv run charmant list tools for the full current list with descriptions.

Auditability

Every session writes an append-only JSONL audit file recording tool selections, permission decisions, execution results, and mode changes. Tool parameters are redacted for secret-looking keys and long values are truncated before being written.

uv run charmant audit list
uv run charmant audit view <session_id>

The point is not only debugging. In agent systems, auditability is part of the control surface. When an agent has access to tools, the system should make it possible to answer what it tried to do, what was approved, what was blocked, and what changed.

Design tradeoffs

Charmant.AI is not a sandbox. It is a local agent with explicit permission gates, audit logging, command classification, and optional executable allow-lists or deny-lists. Those controls reduce accidental risk and make behavior reviewable, but they do not replace OS-level isolation, containers, hardened execution environments, or deployment-time security controls.

That distinction is important: serious agent systems need layered controls. Prompting is not a security boundary.

Technical shape

The charmant command is a small Typer app with three subcommands, plus a no-argument form that launches the TUI:

uv run charmant             # launch the interactive TUI
uv run charmant run ...     # run a single prompt, skill, or file and exit
uv run charmant list ...    # list available skills or tools
uv run charmant audit ...   # inspect audit logs

The TUI provides a persistent conversational session with multiline input, slash commands, model switching, permission-mode switching, plan mode, cancellation, and skill autocomplete. Single-shot runs are available through charmant run <target>, where the target can be a skill, a prompt file, or a plain natural-language instruction.

All settings live in one Settings model, layered with clear precedence: project-local ./.charmant/settings.yaml overrides user-global ~/.charmant/settings.yaml, which overrides environment variables. Key settings include the model, permission mode, sampling parameters, audit logging, and shell allow/deny-lists.

Try it locally

Charmant.AI requires Python 3.13+, uv, and a Gemini API key exposed as GOOGLE_API_KEY.

uv sync
cp .env.sample .env
# edit .env and set GOOGLE_API_KEY=...
uv run charmant

Or run a single prompt and exit:

uv run charmant run "what's using the most memory right now?"

The full command reference, settings reference, tool list, and development notes live in the README.

What this project reflects

Charmant.AI reflects how I think about production AI-agent systems: capability is only half the architecture. The other half is control — what the agent can access, what it can change, when a human must approve, how risky actions are classified, and what evidence is left behind afterward.

Those same questions show up in enterprise agent systems, AWS-hosted AI workloads, internal automation platforms, and AI-native engineering workflows.

Get involved

Charmant.AI is open source and under active development. Clone the repository, run it locally, and try it against a real project or operational workflow — issues and pull requests are welcome at github.com/ilich/charmant.ai.