Skip to main content

gmlw

A metering wrapper around your ML coding CLI

Run claude, cursor, codex, or vibe exactly as you know them — but on a job you tag, in a named, resumable session, with every turn's tokens and cost recorded. An application that uses an ML client, not an ML client pretending to be an application.


License: Apache 2.0 CI Coverage Python

client: claude client: cursor client: codex client: vibe


Why a wrapper  •  Clients  •  The job  •  Install  •  Workflows  •  What it records  •  Guides  •  Design



Why a wrapper

The raw coding CLIs are black boxes. A session has no name you chose, so you can't find it again. A run's cost is invisible — you never learn what a task actually spent. The exact context a session launched with is gone the moment it starts. And every client does all of this differently, so nothing you learn about one transfers to the next.

gmlw is a thin, deterministic shell around the client that keeps the client's behaviour intact and adds the parts an application needs:

  • Identity — you enter at a job you tag; the wrapper mints a named, resumable session on the client.
  • Metering — a local relay sits between the client and its upstream API and records tokens and cost per turn, for any metered client, without changing a single thing about how the client runs.
  • Provenance — the compiled context a session launched with is written to disk; opt in to a full transcript and every call's request, response, and usage is kept too.
  • One surface — claude, cursor, codex, and vibe are all driven the same way and land in the same ledger.

The judgment stays in the client. The deterministic parts — session identity, launch, context compilation, persistence, metering — are Python you can read.

gmlw export — per-turn tokens and cost for a job

Clients at a glance

Four clients, one surface — but they are not identical. What each supports today:

Client Metering Resume Status line Context delivery
claude (claude) native --append-system-prompt-file
cursor (cursor-agent) context-file instruction
codex (codex) ✅ ¹ initial instruction
vibe (vibe) initial instruction

¹ Codex resumes from its first completed turn onward: it mints its own session id, which the wrapper binds off the wire rather than handing it one at launch.

Cursor isn't metered by the open-source wrapper (its usage isn't on an interceptable API); Vibe doesn't resume. See docs/CLIENTS.md for the per-client detail and setup.

The job

A job is the one concept everything hangs off. It's the piece of work you're tagging — a ticket, a refactor, an investigation — and it is the primary key of the whole ledger.

job  ──►  sessions  ──►  turns ──► tokens + cost
                    └───► context.md (what it launched with)
                    └───► transcript (opt-in: in / out / usage per call)

You start work at a job and read it back by job:

gmlw start REFACTOR-42                 # mint + launch a session on the default client
gmlw start REFACTOR-42 --resume-latest # pick the latest session back up
gmlw jobs                              # every job with recorded activity
gmlw sessions REFACTOR-42              # that job's sessions, oldest first
gmlw export REFACTOR-42                # per-turn tokens + cost, totalled by model

Nothing about the client changes — you get its full TUI. The wrapper owns the identity, the launch, and the persistence around it.

Install

Requires Python 3.11–3.14 and uv, plus one supported coding CLI already installed and logged in (claude, cursor-agent, codex, or vibe). The console script is gmlw.

uv tool install generic-ml-wrapper     # or: uv sync --extra dev  (from a clone)
gmlw start MY-FIRST-JOB                # first run self-seeds ~/.gmlw (owner-only)

On first run the wrapper creates ~/.gmlw/ (mode 0700) with a commented config.toml, a SQLite ledger, and the workflow, profile, environment and template folders. Pick the client per run with --client claude|cursor|codex|vibe, or set a default in config.toml.

Workflows

A workflow is a small operating context you author once and launch a job with. Rather than re-explaining the same standing instructions to the client every time, you compile them once — a base, your profile, the rules of your environment and role, and the workflow's own steps — into the context the session opens with.

gmlw workflow new doc-review           # author a workflow (an authoring session, kept apart from work)
gmlw workflow list                     # the runnable workflows
gmlw start DOCS-1 --workflow doc-review # launch a job with that context compiled in

Workflows can carry their own credentials (gmlw creds set <workflow> <ENV_VAR>), injected into the child process at launch and stored 0600. Context compilation runs through an interceptor chain, so a step like context compression is an opt-in plug-in, not a fork of the engine.

What it records

Everything lives under ~/.gmlw/, owner-only, on your machine:

Artifact Where What
Ledger ledger.db (SQLite, WAL) jobs, sessions, per-turn token usage, per-session cost
Context contexts/<job>/<session>.context.md the exact compiled context the session launched with
Transcript (opt-in) transcripts/<job>/<session>/call_NNN.{in.json,out.sse,usage.json} every call's request, response, and usage — a portable, self-contained folder

For Claude Code and Cursor, the wrapper renders a rich status line straight into the client's own status bar — the git branch, folder, model, context %, and live cost, plus the job's running total. (The status-line seam is client-agnostic; Claude and Cursor are wired today, and other parsers can be added.)

the gmlw status line rendered for claude and cursor

Your operating context, carried across clients

Beyond metering, gmlw builds a portable operating context that follows you from one client to the next — none of it locked inside a single tool:

  • Profile & company — who you are and your project's conventions (profile/me, profile/company), composed into every session.
  • Learned notebook — what your tools notice about how you work, in one file they all mirror into; negatives ("what to avoid") are first-class.
  • Personas — a selectable tone with a free, local greeting at launch (gmlw persona list).
  • Rules — corrections you've demanded, captured as reusable reflexes and filed by axis: the environment's constraints (~/.gmlw/environments/<env>/rules/) or your role's craft preferences (~/.gmlw/profile/roles/<role>/rules/). Browse them with gmlw tui → Rules.
  • Mode-aware packaging — a [startup.<mode>] matrix decides which sources compose for a plain session, a workflow, or authoring, with optional typed compression.
  • Plugins & overrides — swap a client's caller by id (gmlw plugins list, [callers]).

Workflows (above) are optional and separate from this personal layer. Every listing/reporting command also speaks --json for automation.

What gmlw does not do

  • It is not a sandbox — it launches the real client with your credentials (see SECURITY.md).
  • It does not meter Cursor, and does not resume Vibe (see the matrix).
  • It does not call models itself — the optional context compressor records through generic-ml-cache.
  • It ships no compression prompts — the compressor stays inert until you configure one.

Guides

Develop

The gates are defined once in noxfile.py; CI is a thin caller of them, so what runs locally is byte-for-byte what runs in CI.

uv sync --extra dev          # or: nox -s dev   (builds the IDE .venv)
nox                          # lint · imports · typecheck · tests (3.11–3.14)
nox -s green                 # the whole gate in one env (lint · format · imports · pyright · coverage)

Strict ruff + pyright (over src and tests), import-linter hexagon contracts, and an 80% coverage floor all run in the gate. Every change goes on a branch (feature/… tech/… fix/… docs/… chore/… test/…), keeps nox -s green passing, and merges via PR — direct pushes to main are blocked by branch protection.

See docs/DESIGN.md for the architecture, SECURITY.md for the threat model, and CONTRIBUTING.md to get set up.

Family

Part of the generic-ml-* family, alongside generic-ml-cache (record/replay execution cache — the wrapper's context compressor records through it) and generic-ml-workflow.

License

Apache-2.0 — see LICENSE and NOTICE. Contributions welcome; see CONTRIBUTING.md.

Release files for generic-ml-wrapper 0.9.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for generic-ml-wrapper 0.9.1
File Size Uploaded
generic_ml_wrapper-0.9.1.tar.gz 711.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for generic-ml-wrapper 0.9.1
File Interpreter ABI Platform
generic_ml_wrapper-0.9.1-py3-none-any.whl Python 3 none any Details

Total release size: 1.1 MB

Release files / generic_ml_wrapper-0.9.1.tar.gz

Download URL generic_ml_wrapper-0.9.1.tar.gz
Size 711.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ead09e637b71bd6a2141c6b3de2eb2cb78ef7900a72cd1c9d67eccd130b3d253
BLAKE2b-256 checksum
How to use checksums
d9774eb5a739c236c4cd234da2fc5010babf48a3cc898b320a3888e5ceef4bfd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / generic_ml_wrapper-0.9.1-py3-none-any.whl

Download URL generic_ml_wrapper-0.9.1-py3-none-any.whl
Size 376.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9403e16a1b78eaf56b5dea26a4cad9c16deb078eb9deddac9986513104fccb33
BLAKE2b-256 checksum
How to use checksums
43aa1e5b992336395b1d4e6837fc33fb9ef09e7862e377805273d104918ccf9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.9.1 This release

2 release files

0.9.0

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page