{"slug": "halyard-open-ai-work-ledger-for-developers-time-tokens-cost-invoices", "title": "Halyard – open AI work ledger for developers (time, tokens, cost, invoices)", "summary": "Halyard, an open-source AI work ledger for developers, launched in alpha to track time, tokens, cost, and invoices across AI tools like Claude Code and Cursor. The tool captures session metadata as plain text on the user's machine, enabling cost breakdowns and invoice evidence without storing prompts or code. It targets freelancers and small AI shops seeking auditable AI spend records.", "body_md": "A halyard is the line that raises the sails. Pull on it, the sails go up. Pull on this one, your AI work comes into focus.\n\n**Your AI work leaves a trail. Halyard makes that trail legible, auditable, and client-safe.**\n\nEvery AI session — time, tokens, model, cost, project — captured where the work happens, stored as plain text on your machine, owned by you. No account. No cloud service. No prompt or code capture. Ever. MIT licensed.\n\n**Status:** alpha, open source — capture loop, reports, invoices, The Bridge, and TUI\nin daily use.\n\nYou're doing AI-assisted work. At the end of a sprint, a month, or a client engagement, you can't answer three basic questions:\n\n- What did AI actually cost on this project?\n- What did AI help produce — and can you prove it?\n- Is your AI spend going in the right direction?\n\nYour tools don't record this. Halyard does.\n\nIt runs as lightweight hooks inside Claude Code, Cursor, and Gemini CLI, with manual/editor-task capture for tools like VS Code where no public AI-session hook exists. Every session writes one line to a plain-text log you own. From that log: cost breakdowns, project attribution, invoice evidence, and eventually a signed, verifiable AI work appendix you can hand to a client.\n\nThe privacy promise is unconditional: Halyard captures session metadata, never prompt content, code context, file contents, or transcripts.\n\n**Individual developers and freelancers** — your primary audience right now.\nYour time, your AI spend, and your invoice evidence live as plain text on your\nlaptop. Halyard helps you prove what happened without exposing prompts or code.\nGit it, back it up, sync it however you want. No account. No SaaS. No\nproprietary format.\n\n**Small AI shops** — share the same local ledger format across a team.\nProject spend, trust-labeled cost allocation, and client-safe appendices built\nfrom individual plain-text logs.\n\n**Enterprise** — the same format will support governance, cost centers, and\ncross-tool AI Work Intelligence later. That layer is additive, gated on\ndesign-partner pull, and will not change what local files mean.\n\nHalyard has three layers:\n\n**Collection** — Lightweight hooks that run where AI work happens. Claude Code,\nCursor, Windsurf, and Gemini CLI hooks capture sessions automatically; a VS Code\nextension captures editing time, branch, and code delta — token counts\nunavailable until VS Code/Copilot exposes a public session hook. Since v3.5,\nClaude Code sessions are tagged with an advisory **client surface**\n(`cli`\n\n/ `desktop`\n\n/ `ide`\n\n) detected from the local environment. Captured fields\ninclude time, tokens when available, model, cost, project, and branch. Written\nto a plain-text log you own. New sessions are appended, and the current\nhardening track is making corrections explicit and auditable. Nothing is lost\nsilently.\n\n**Intelligence** — Analytics built on that log. Local CLI reports, cost-by-project breakdowns, per-model spend, budget alerts, and trust-labeled totals (captured vs. calculated vs. allocated). Works offline, no account required.\n\n**AI Work Ledger** — Cost allocation for seat subscriptions and credit plans. If you pay $200/month for Claude Max, Halyard allocates that cost across your projects proportionally — by active minutes, session count, or credit usage — so you know what each client engagement actually costs. Runs on top of `ai-sessions.log`\n\nand `ai-plans.toml`\n\n; nothing is written back to the raw log.\n\n**Proof Artifacts** — Invoice evidence today, and a signed attestable AI work\nappendix next. The goal is a client-safe artifact that proves AI-assisted work\nwithout showing prompts, transcripts, source code, or file contents.\n\n**The Bridge** — A local dashboard for watching capture happen in real time. Run `halyard dashboard`\n\ninside any Halyard project.\n\n**Rich Session Telemetry** — Where tools expose it, Halyard captures operational metadata beyond cost: tool call counts, error rates, wall time vs. active agent time, code delta, and per-model breakdowns. Gemini CLI sessions include full multi-model breakdowns from the history file. These signals surface in the TUI and The Bridge as work-health indicators — not productivity scores, but honest signals of session shape.\n\n**Honors** — A service record that rewards clean proof, not raw hours. Ranks advance on attributed sessions (Deckhand → Commodore), stripes track your watch streak, and eight medals recognize behaviors that matter: completing your first watch, keeping a clean manifest, rescuing adrift sessions, and more. Run `halyard honors`\n\nto see your record.\n\n**Friends of the Sea** — One sea creature per completed project, auto-assigned by personality. Projects move through nautical voyage stages (Anchors Aweigh → Making Headway → Rounding the Mark → Flying Colors → Shipshape · Moored) as sessions accumulate. Auto-completes on target hit or inactivity. Run `halyard voyage`\n\nto see the roster. Your Captain's Quarters on The Bridge shows a Passport — one stamp per AI tool you've used.\n\nHalyard is a Python 3.11+ local-first CLI and dashboard, not a hosted billing\nservice. The `halyard`\n\ncommand is a Typer app, reports use Rich, the terminal\ndashboard uses Textual, and The Bridge is a small `127.0.0.1`\n\nHTTP\nserver. The durable data model is plain text in the project folder; SQLite is\nonly a rebuildable read-model cache for faster queries.\n\nThe capture pipeline is intentionally simple:\n\n``` php\nAI tool hook/importer/manual command\n  -> normalized AiSession object\n  -> append-focused ai-sessions.log line\n  -> reports, ledger allocation, dashboard, invoice evidence\n```\n\nSo: is Halyard \"just looking at logs\"? Not exactly. It uses the best public signal each tool exposes:\n\n**Claude Code**: installs`UserPromptSubmit`\n\nand`Stop`\n\nhooks. The start hook records session start time and git SHA. The stop hook reads the structured hook payload; for newer Claude Code formats it can also aggregate token/model metadata from the local transcript JSONL path passed by the hook.**Cursor**: installs`beforeSubmitPrompt`\n\nand`stop`\n\nhooks. It reads the stop payload and prefers`workspace_roots`\n\nfor attribution because that is the actual editor workspace, not necessarily the shell CWD.**Gemini CLI**: installs`SessionStart`\n\n,`AfterModel`\n\n, and`AfterAgent`\n\nhooks.`AfterModel`\n\naccumulates token usage from`usageMetadata`\n\n;`AfterAgent`\n\nfinalizes the session. It integrates deeply with OpenTelemetry (OTLP) to measure exact API and tool-execution durations (`api_seconds`\n\n,`tool_seconds`\n\n) and enriches from Gemini's local history file for accurate multi-model token breakdowns, tool-call counts, and deterministic cost.**Codex Desktop**: imports local`~/.codex/sessions/.../rollout-*.jsonl`\n\nfiles, extracts timing/model/token metadata, and records imported session IDs so repeated imports do not duplicate entries.**VS Code / GitHub Copilot**: a local VS Code extension (`vscode-extension/`\n\n) tracks active editing time, captures branch and code-delta via git, and writes sessions through`halyard record-session`\n\n. Install the extension from a local`.vsix`\n\nbuild; no public Copilot session hook exists yet so token counts are not available.\n\nEvery collector writes the same normalized record shape: timestamps, tool,\nmodel, tokens when available, cache tokens, cost, billing type, project,\nbranch, capture source, and attribution provenance. Halyard does not store\nprompts, source code, file contents, or full transcripts in `ai-sessions.log`\n\n.\nWhen a collector temporarily reads a local transcript or history file, it is\nonly to extract session metadata.\n\nThe log is append-focused. Session records are `s ...`\n\nlines; corrections are\nseparate amendment records keyed by a hash of the original line. Writers\nhold an exclusive OS-level file lock (`fcntl.flock`\n\non POSIX, `msvcrt.locking`\n\non Windows) so concurrent hooks do not interleave writes. Malformed records\nare quarantined instead of crashing report generation.\n\nCost handling is explicit about trust. Direct API usage can be captured or\ncalculated from tokens and the local pricing table. Seat or credit plans are\nallocated at report time from `ai-plans.toml`\n\nby active minutes, session count,\nor credits. Reports label the result as captured, calculated, allocated,\ninferred, mixed, or unallocated so client-facing evidence does not pretend an\nestimate is a measurement.\n\nPlatform:macOS, Linux, and Windows. The`halyard service install`\n\ncommand is macOS-only; other platforms can run`halyard dashboard`\n\nin a long-lived terminal instead.\n\n```\npipx install halyard\ncd ~/businesses/my-freelance\nhalyard init\n\n# Guided setup installs supported hooks and checks readiness:\nhalyard setup\n\n# Verify your hooks and first capture:\nhalyard doctor --first-capture\n\n# Open the dashboard\nhalyard dashboard\n# Start your human timer (AI sessions are auto-captured in the background)\nhalyard start acme/auth-migration\n# ... do work ...\nhalyard stop\n\n# Terminal UI\nhalyard tui\n\n# Ask in natural language — two ways, both read-only:\nhalyard log \"what did I spend this month?\"   # from the CLI (local by\n                                             # default; --agent claude|openai optional)\n#   …or via your coding agent through the MCP server (see below)\n\n# Generate an invoice with an AI usage evidence appendix\nhalyard invoice acme --month 2026-05 --include-ai-evidence\n```\n\n**View Full Command Reference**\n\n```\n# Stats-forward analytics — sessions, streaks, peak hour, model mix\nhalyard usage --range 30d\nhalyard usage --range 7d --json   # machine-readable\n\n# --json on report/usage/budget/status/evidence/health/doctor for CI + scripts\nhalyard report --all --json | jq '.totals.cost_usd'\nhalyard budget --json | jq '.[] | select(.month.state==\"over\")'   # spend gate\n\n# Install the background launchd service (macOS):\nhalyard service install\n\n# Ask your agent about your own AI work (read-only MCP server):\npipx inject halyard mcp   # add the MCP extra to the pipx install\nhalyard mcp            # stdio MCP server for Claude Code / Cursor\n\n# Install hooks manually:\nhalyard install-hook          # Claude Code\nhalyard install-cursor-hook   # Cursor\nhalyard install-gemini-hook   # Gemini CLI\nhalyard install-vscode-tasks  # VS Code manual capture task\n\n# Record VS Code/Copilot work manually\nhalyard record-session --tool vscode --model github-copilot --minutes 15 --note \"Copilot chat\"\n\n# Retroactive Gemini import\nhalyard import-gemini\n\n# Budget limits\nhalyard set-budget acme --daily 10.00 --monthly 200.00\n\n# AI Work Ledger — allocate seat/credit plan costs by project\nhalyard report --ledger\n\n# Confirm inferred project attribution from timeclock overlap\nhalyard confirm-attribution\n\n# Keep pricing table fresh\nhalyard update-pricing\n\n# Service record & Project voyage roster\nhalyard honors\nhalyard voyage\n```\n\nSee [ docs/demo.md](/Kormiloio/Halyard/blob/main/docs/demo.md) for a full walkthrough — self-guided and\nlive presentation script in one document. If capture does not show up, start\nwith\n\n[.](/Kormiloio/Halyard/blob/main/docs/troubleshooting.md)\n\n`docs/troubleshooting.md`\n\n`halyard mcp`\n\nruns a **read-only** MCP server over stdio so Claude Code,\nCursor, or any MCP client can query your local ledger in-context — e.g.\n\"how much did I spend this week?\", \"did this work ship?\", \"what's my\nadrift rate?\". It exposes `work_summary`\n\n, `sessions`\n\n, `spend_in_range`\n\n,\n`project_breakdown`\n\n, `cost_by_model`\n\n, and `outcomes_status`\n\n. No tool\nwrites anything; only metadata already in the ledger is returned (never\nprompts, code, or transcripts). It needs the optional extra\n(`pipx inject halyard mcp`\n\n, or `pipx install 'halyard[mcp]'`\n\nfrom a\nfresh install).\n\n`halyard init`\n\n(and `halyard setup`\n\n) **auto-registers** it with every\nMCP client detected on your PATH — Claude Code, Cursor, Gemini CLI — so\nyou never edit a config file. Re-run any time, or register one client\nexplicitly:\n\n```\nhalyard install-mcp-claude     # or -cursor / -gemini\n```\n\nIt writes a single `mcpServers.halyard`\n\nentry to each client's config\n(`~/.claude.json`\n\n, `~/.cursor/mcp.json`\n\n, `~/.gemini/settings.json`\n\n),\npreserving every other server. The Halyard repo also ships a ready\n[ .mcp.json](/Kormiloio/Halyard/blob/main/.mcp.json) for Claude Code zero-config pickup in-repo:\n\n```\n{ \"mcpServers\": { \"halyard\": { \"command\": \"halyard\", \"args\": [\"mcp\"] } } }\n```\n\n| Tool | How it's captured | Status |\n|---|---|---|\n| Claude Code | `Stop` hook — fires on every session end |\nShipped |\n| Cursor | `stop` hook — fires when agent completes |\nShipped |\n| Gemini CLI | `SessionStart` / `AfterModel` / `AfterAgent` hooks + history file enrichment |\nShipped |\n| Codex Desktop | JSONL session importer | Shipped |\n| VS Code / GitHub Copilot | VS Code task + `record-session --tool vscode` ; no public Copilot hook yet |\nManual capture |\n| Windsurf | TBD | Future |\n| OpenAI API direct | SDK wrapper or proxy | Future |\n\nGemini CLI sessions include per-model token breakdowns (flash vs. pro vs. thinking), tool call counts, and accurate multi-model cost — derived from the same history file Gemini CLI uses for its own shutdown summary.\n\nTools that are not written in Python can emit sessions directly to the local Hub:\n\n```\nhalyard spec\nsamples/emit-session.sh\n```\n\nThe Hub accepts `POST http://127.0.0.1:4318/v1/ingest`\n\nwith either a raw\ncanonical `ai-sessions.log`\n\nline or a structured `fields`\n\nobject. Structured\npayloads must include `start`\n\n, `end`\n\n, `tool`\n\n, `model`\n\n, `input_tokens`\n\n,\n`output_tokens`\n\n, and `cost_usd`\n\n; optional metadata keys are the same keys shown\nby `halyard spec`\n\n.\n\n```\ncurl -X POST http://127.0.0.1:4318/v1/ingest \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"fields\":{\"start\":\"2026-05-23T10:00:00\",\"end\":\"2026-05-23T10:05:00\",\"tool\":\"custom-tool\",\"model\":\"model-x\",\"input_tokens\":100,\"output_tokens\":50,\"cost_usd\":0.01}}'\n```\n\nPer session (one line in `ai-sessions.log`\n\n):\n\n- Start and end time\n- Tool (\n`claude-code`\n\n,`cursor`\n\n,`gemini-cli`\n\n,`vscode`\n\n, …) - Model identifier\n- Input tokens, output tokens, cache read/write\n- Cost in USD (from local pricing table, snapshotted at capture)\n- Project attribution (\n`client:project`\n\n) - Git branch\n- Billing model (\n`api`\n\n,`credits`\n\n,`seat`\n\n) - Capture source (\n`hook`\n\n,`sdk`\n\n,`manual`\n\n)\n\nWhat is **not** captured: prompt content, code context, file contents, any user data beyond session metadata.\n\nSet per-project spend limits in your personal `~/.halyard/budgets.toml`\n\n— never committed to the repo. Warnings fire at session start when you've exceeded a daily or monthly threshold. Sessions always proceed; this is instrumentation, not a gate.\n\n```\nhalyard set-budget acme --daily 15.00 --monthly 300.00\nhalyard budget   # shows current spend vs limits across all projects\nmy-business/\n├── halyard.toml          # business name, currency, invoice counter\n├── clients.toml          # array of clients\n├── projects.toml         # array of projects\n├── time.timeclock        # hledger-compatible human time log\n├── ai-sessions.log       # AI usage events (plain text, append-focused)\n├── ai-plans.toml         # seat/credit plan definitions for cost allocation\n└── invoices/             # generated invoice markdown + PDF\n```\n\nAgent state (hooks, API keys, budgets, active timer) lives in `~/.halyard/`\n\n, separate from the project folder.\n\nSome captured sessions don't carry token data. The dashboard flags them as\n`missing tokens`\n\nand `halyard usage`\n\nreports them under\n`token_data_missing_sessions`\n\n. Common reasons:\n\n**Claude Code seat sessions**— when a session is on a credits/seat plan rather than the API, token counts may not be available in the hook payload. The session is still recorded with`tokens_available=false`\n\n; cost is reported as`$0.00`\n\nbecause there is no per-session API charge. Use[the AI Work Ledger](#what-gets-captured)(`halyard report --ledger`\n\n) to see allocated subscription cost for these.**Manual or VS Code editor-task captures**— sessions recorded via`halyard record-session`\n\nwithout an explicit`--input-tokens`\n\n/`--output-tokens`\n\narrive without token data. This is expected; the capture is preserved for time/attribution.**Codex imports**— the Codex Desktop import path reads from the local rollout JSONL but may not surface token counts in all session formats. Import is still useful for attribution and time.\n\nThese rows are **not** quarantined and **not** lost — they appear in the\nlog with `tokens_available=false`\n\nso downstream tooling can distinguish\n\"no data\" from \"zero usage\".\n\nHalyard records two cost classes:\n\n**Direct API cost**(`cost_usd`\n\non the session line) — per-call charge from the provider, captured when the hook payload includes pricing.**Allocated subscription cost**— your $20/month Claude Pro or $200/month Claude Max is allocated across captured sessions proportionally. Run`halyard report --ledger`\n\nto see this. Cost trust labels in the dashboard (`captured`\n\n/`calculated`\n\n/`allocated`\n\n) tell you which lens you're looking through.\n\nIf `cost_usd`\n\nis consistently $0.00 *and* you have no `ai-plans.toml`\n\n,\ncreate one in the project folder (define your seat/credit plans) so\n`halyard report --ledger`\n\ncan allocate subscription cost.\n\nThat's the same `token_data_missing_sessions`\n\ncount surfaced as a pill on\nthe Usage Analytics panel. It's a counter, not an error — see \"missing\ntokens\" above. If the number is climbing, check that your active AI tool's\nhook is sending token data (`halyard doctor`\n\nconfirms hook health) and\nthat recent sessions on the API plan aren't being dropped.\n\nThis project uses [OpenSpec](https://github.com/Fission-AI/OpenSpec) for spec-driven development. Every feature lives as a change folder under `openspec/changes/`\n\nwith a proposal, specs, design, and task checklist.\n\nVersioning note:the published PyPI package is`0.x`\n\n(currently`0.2.1`\n\n). The`vN.x`\n\nidentifiers below (e.g.`v2.24`\n\n) are internal OpenSpec changeset IDs,notrelease versions — they track design history, not what you`pipx install`\n\n.\n\n| Change | Description |\n|---|---|\n| - | No active focus; all current changes shipped. |\n\n| Change | Description |\n|---|---|\n`v3.6-windsurf-collector` |\n\n`v3.5-claude-code-surface`\n\n`v0-time-and-invoice`\n\n`halyard init`\n\n, human time tracking, invoice generation`v0.1-log-and-invoice`\n\n`halyard log`\n\nnatural-language query + `halyard invoice`\n\n`v0.2-ai-agent-loop`\n\n`halyard log`\n\n`v0.3-provider-neutral-log`\n\n`halyard log --agent openai`\n\n`v1-ai-intelligence`\n\n`v1.5-multi-tool-collectors`\n\n`v2-ai-work-ledger`\n\n`confirm-attribution`\n\n, invoice evidence appendix`v2-local-activity-dashboard`\n\n`halyard dashboard`\n\n)`v2.1-dynamic-pricing`\n\n`halyard update-pricing`\n\n— live pricing table sync`v2.2-budget-limits`\n\n`v2.3-gemini-history`\n\n`halyard import-gemini`\n\n`v2.4-data-integrity`\n\n`v2.5-cli-decoupling`\n\n`v2.6-rich-session-telemetry`\n\n`v2.7-ai-work-health`\n\n`v2.8-calendar-blocks`\n\n`v2.9-onboarding-doctor`\n\n`halyard doctor`\n\nsetup diagnosis`v2.10-guided-setup`\n\n`v2.11-hook-normalization`\n\n`v2.12-glass-cockpit-service`\n\n`v2.13-backtracking-attribution`\n\n`v2.14-sqlite-read-model`\n\n`v2.15-transaction-history`\n\n`v4-tui`\n\n`halyard tui`\n\n)`v2.16-distribution-and-security`\n\n`v2.17-log-integrity`\n\n`v2.18-cache-and-audit-hardening`\n\n`v2.20-security-remediation`\n\n`v2.21-attribution-provenance`\n\n`attr_method`\n\n) for billing and audit clarity`v2.22-security-architecture`\n\n`v2.23-usage-analytics`\n\n`v2.24-outcome-metadata`\n\n`halyard outcome sync`\n\n)`v2.25-honors-and-achievements`\n\n`halyard honors`\n\n)`v2.26-passport-and-friends`\n\n`halyard voyage`\n\n)| Change | Description |\n|---|---|\n`v3.0-outcome-graph` |\n\n`v3-org-admin-dashboard`\n\n**Shipped**— OSS launch (v0.2.1), honors and achievements (`halyard honors`\n\n), Passport stamps, Friends of the Sea voyage stages (`halyard voyage`\n\n), outcome metadata v2.24: branch field, commit count, code delta,`halyard outcome sync`\n\n, and Claude Code client-surface detection (v3.5).**Then**— Attestable AI work appendix (v2.19): signed, client-safe proof of AI-assisted work, enriched with commit and PR signals.**Later, if design partners ask**— Outcome graph (v3.0): connect sessions to commits, PRs, tests, and deliverables.** Further out**— Redacted sync, org rollups, governance, finance exports, and enterprise reporting.\n\nThese hold at every tier:\n\n**Local-first.** The core product runs offline. Cloud is optional and additive.**Plain text forever.** Your data is yours, in formats that outlast any startup.**Files are the source of truth.** No hidden state, no proprietary database.**Append-only direction.** New sessions are appended. Corrections are explicit and auditable; attribution cleanup is being hardened toward append-only correction records.**No silent writes.** Every AI-proposed change is shown before it's applied.**MIT licensed.** Permissively. Forever.\n\nEarly but open. The project uses [OpenSpec](https://github.com/Fission-AI/OpenSpec)\nfor spec-driven development — every feature has a `proposal.md`\n\n, `design.md`\n\n,\n`specs/`\n\n, and `tasks.md`\n\nbefore code is written. See `openspec/changes/`\n\nfor\nwhat is actively being built.\n\n**To contribute:**\n\n- Browse\n`openspec/changes/`\n\nfor open changesets. - Check the\n`tasks.md`\n\nin any changeset for unchecked items. - Open an issue before a PR if you are proposing a new feature — start with a one-paragraph proposal so we can align on fit before you write code.\n- Bug reports and docs improvements need no prior discussion.\n- The test suite is\n`pytest`\n\n; coverage requirements are enforced. Run`python -m pytest`\n\nbefore submitting.\n\nIf something is confusing, a docs issue is as valuable as a code PR.\n\nMIT.\n\nA [Kormilo LLC](https://kormilo.io) project.", "url": "https://wpnews.pro/news/halyard-open-ai-work-ledger-for-developers-time-tokens-cost-invoices", "canonical_source": "https://github.com/Kormiloio/Halyard", "published_at": "2026-06-25 00:47:03+00:00", "updated_at": "2026-06-25 01:14:24.637691+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-infrastructure", "ai-ethics", "ai-products"], "entities": ["Halyard", "Claude Code", "Cursor", "Gemini CLI", "VS Code", "Windsurf", "Copilot"], "alternates": {"html": "https://wpnews.pro/news/halyard-open-ai-work-ledger-for-developers-time-tokens-cost-invoices", "markdown": "https://wpnews.pro/news/halyard-open-ai-work-ledger-for-developers-time-tokens-cost-invoices.md", "text": "https://wpnews.pro/news/halyard-open-ai-work-ledger-for-developers-time-tokens-cost-invoices.txt", "jsonld": "https://wpnews.pro/news/halyard-open-ai-work-ledger-for-developers-time-tokens-cost-invoices.jsonld"}}