Skip to content
Back to skills

Commitment Ledger

ASecurity

Outbound commitments ledger - things the owner said he'd do (from Fathom meeting action items, sent Slack messages, and local meeting transcripts/MOM drafts), tracked from "I'll ..." until actually delivered or dropped. Not for things the owner is waiting on others for (see waiting-watchdog).

  • 33 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 23, 2026
ai-agentspythongobashapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 23, 2026

npx -y skills add BrianArfi/ai-second-brain --skill commitment-ledger --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Commitment Ledger?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Commitment Ledger
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/brianarfi-commitment-ledger/badge)](https://www.skillsdirectory.com/skills/brianarfi-commitment-ledger)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: commitment-ledger
description: Outbound commitments ledger - things the owner said he'd do (from Fathom meeting action items, sent Slack messages, and local meeting transcripts/MOM drafts), tracked from "I'll ..." until actually delivered or dropped. Not for things the owner is waiting on others for (see waiting-watchdog).
---

## Capabilities

- Mechanically pull Fathom action items assigned to the owner from recently-synced meetings
  (`journal/fathom_registry.json`) into high-confidence commitment items - no LLM needed.
- Sweep the owner's own sent Slack messages for commitment language ("I'll send...", "will follow
  up...") into a cheap-filtered candidate queue, then use GLM (via agy-bridge) to extract
  structured commitments (recipient, due date) from that queue.
- Mechanically capture the owner's spoken "this is my action item" cues from local meeting
  transcripts, plus MOM "Action Items" rows that name the owner, into high-confidence commitment
  items - no LLM needed (see **Local meeting-cue capture** below for the exact trigger phrases).
- Mechanically auto-close a commitment when the owner later posts a completion word or a Drive/Docs
  link in the same thread.
- Emit a briefing-ready markdown report (overdue open first, then open by due date, then
  no-due, closed items only with `--all`).

## Local meeting-cue capture

Say ANY of these mid-meeting (Bahasa or English, case-insensitive) and the local recorder's
transcript/MOM draft will mechanically pick it up on the next `sweep` - no LLM, no manual entry:

- `ini action item gw: <what you'll do>`
- `action item gw <what you'll do>` / `action item gue ...` / `action item saya ...`
- `note action item: <what you'll do>` / `note, action item ...`
- `my action item: <what you'll do>`

Everything after the cue phrase, to the end of that line, becomes the commitment text (a
leading `:` or `-` is stripped). Captures under 4 words are dropped as noise (e.g. just saying
the cue phrase with nothing after it, or a transcription artifact). The recipient (`to`) is
always left blank - a spoken cue names an action, not a recipient - so these render as `->`-less
items in `report`; add one later with the ledger's own `close --note` or by editing `to` via a
future manual pass if needed.

Separately, ANY row inside a MOM's "Action Items" section (table row, checkbox bullet, plain
line - whatever format that MOM uses) that contains the literal word "the owner" is also captured.
**Caveat:** this is a blunt word match, not owner-column parsing - parsing which table column
is "Owner" per MOM format would need real understanding, which the mechanical/no-LLM
constraint rules out. So a row like `| Rani | Share X with the owner and Javi | ... |` gets
captured even though the owner is only the recipient named in that row, not the owner. Skim these
before turning one into a ticket.

## Usage

```bash
# cron default: Fathom action items + Slack candidate collection + mechanical auto-close
python3 .agent/skills/commitment-ledger/scripts/commitment_ledger.py sweep

# GLM extraction pass over queued Slack candidates -> structured medium-confidence items
python3 .agent/skills/commitment-ledger/scripts/commitment_ledger.py extract

# manual capture (e.g. a commitment made verbally, or spotted during /mom)
python3 .agent/skills/commitment-ledger/scripts/commitment_ledger.py add \
  --text "Send updated OTO PRD to Teammate" --to "Teammate Sanka" --due 2026-07-14 \
  --project "OTO Logistics" --source "https://fathom.video/calls/..."

# close/drop manually
python3 .agent/skills/commitment-ledger/scripts/commitment_ledger.py close COM-0001 --note "sent via Slack"
python3 .agent/skills/commitment-ledger/scripts/commitment_ledger.py drop COM-0002 --note "no longer relevant"

# briefing-ready markdown (embed verbatim in morning/evening update)
python3 .agent/skills/commitment-ledger/scripts/commitment_ledger.py report
python3 .agent/skills/commitment-ledger/scripts/commitment_ledger.py report --all   # include closed
```

## Notes

- State file: `journal/state/commitments.json` - `{next_seq, items: {COM-NNNN: {...}},
  slack_search_watermark, local_watermark, processed_fathom_ids, processed_sources,
  pending_candidates, user_names, last_sweep}`. `local_watermark` (epoch float) is the local
  meeting-cue source's watermark, parallel to `slack_search_watermark` - the newest mtime
  (across all scanned files) seen by the most recent `sweep`.
- IDs are human-typeable and monotonic: `COM-0001`, `COM-0002`, ...
- Item schema: `{id, text, to, to_slug, channel, channel_name, thread_ts, permalink, due,
  project, source: {type: fathom|slack|manual|meeting-local, ref}, status: open|done|dropped,
  confidence: high|medium, first_seen, closed_at, closed_by, priority, notes[]}`.
  `to_slug` = `slugify(to)` (lowercase-dash) so this ledger can cross-reference
  `journal/state/people.json` (owned by the `stakeholders` component) by slug without a
  hard dependency - resolve by slug, fall back to the free-text `to` name.
- **Fathom path gotcha (confirmed 2026-07-10):** `fathom_client.py --action get --id
  <recording_id>` 404s for every recording_id currently in `fathom_registry.json` on this
  deployment (tried 2 recent IDs, both 404 on both `/meetings/` and `/recordings/`
  endpoints). `--action list --full` DOES return `action_items[]` per meeting (confirmed
  shape: `{description, user_generated, completed, recording_timestamp,
  recording_playback_url, assignee: {name, email, team}}`). `sweep_fathom()` therefore uses
  `list --full` (bounded `--limit`, default 20) and cross-references against
  `fathom_registry.json` to identify which fetched meetings are new, rather than fetching
  per-recording via `get`. the owner-assignee match: `assignee.email == you@example.com` OR
  assignee name contains `"owner arfi"`/`"you"` (case-insensitive - Fathom's
  transcript speaker-matching produces inconsistent casing/fullname variants, e.g. "owner
  arfi" vs "Your Name").
- Slack sent-message sweep: `search.messages from:<@<SLACK_ID>>` (the owner's verified Slack
  ID), paginated (bounded to 5 pages/sweep), cheap regex pre-filter (`COMMIT_RE`) so
  `pending_candidates` doesn't fill with unrelated sent messages. First run looks back 3
  days. Extraction into real ledger items is NOT done during `sweep` - only `extract`
  (GLM via agy-bridge) turns a candidate into a `COM-*` item, confidence `medium`.
  Fathom-sourced items are confidence `high` (mechanical, no LLM).
- Local meeting-cue sweep scans (verified against `meeting-recorder/watcher.py` constants,
  do not guess): `Clients/Work/meetings/transcripts/*.md` (raw local/vexa transcripts),
  `Clients/Work/meetings/*.md` (MOM drafts - same dir the watcher + `/mom` write to), and
  `Clients/*/meetings/*.md` (any other client's meeting notes, present or future). `.md` only
  - the `.txt` whisper sidecars in the transcripts dir are not scanned. Only files with
  `mtime` newer than `local_watermark` are read each sweep (first run: 3-day lookback, same
  as Fathom/Slack). Two independent captures per file: (1) `CUE_RE` finds the owner's spoken
  cues anywhere in the text; (2) `extract_mom_action_lines()` finds the "Action Items"
  heading (heading-level aware, so a nested subheading doesn't end the section early) and
  scans its rows for the literal word "the owner". Dedupe key: `local:<repo-relative
  path>:<sha1(raw line)[:12]>` in `processed_sources` - content-hashed per line, so
  re-touching a file (e.g. a later hand-edit of a MOM) only re-captures genuinely new/changed
  lines, not ones already ingested. Confidence `high` (mechanical, no LLM, same tier as
  Fathom). `permalink` and `source.ref` are both set to the repo-relative path so `report`
  renders a clickable local link (`[ref](Clients/Work/meetings/...)`), consistent with how
  the owner opens local files from this harness.
- agy-bridge contract: rc 0 -> stdout has JSON lines to parse. rc 3 -> `FALLBACK_TO_CLAUDE`
  marker printed, `pending_candidates` left untouched, exit 0 (NOT a failure - Claude
  should run `extract`'s judgment manually in that case, same pattern as
  `mention_ledger.py cmd_classify`).
- Auto-close is mechanical only: an open item with a `channel` + `thread_ts` gets closed
  (`closed_by: auto_thread`) when the owner's own later message in that thread contains a
  completion word (done/sent/shared/delivered/...) or a `docs.google.com`/`drive.google.com`
  link. Fathom-sourced items have no `thread_ts` (the API gives no recipient thread) so they
  can only be closed via `close`/`drop`.
- Retention: `done`/`dropped` items pruned after 14 days (`CLOSED_RETENTION_DAYS`). Stale
  unconsumed `pending_candidates` (>14d, never `extract`-ed) are also dropped as likely
  superseded.
- `report` ordering: (1) overdue open (`due` < today WIB), (2) open by due date ascending
  (no-due items after all dated ones), (3) with `--all`, closed items last by close time.
- This skill never writes to `tickets.json`, the mention ledger, `people.json`, or any
  other component's state - read-only relationship elsewhere is by slug/id cross-reference
  only (see `to_slug`).
- Cron (design only - NOT installed by this skill): `10 9,14,20 * * * flock -n
  /tmp/commitment_ledger.lock python3 <abs>/commitment_ledger.py sweep >>
  .agent/skills/commitment-ledger/commitment_ledger_cron.log 2>&1` then a second `extract`
  invocation in the same flock line (`sweep && extract`), off the `:00`/`:30` marks so it
  doesn't collide with `mention_ledger`'s `*/30` cron.
- Heartbeat: `sweep` calls `.agent/scripts/heartbeat.py --job commitment-ledger --status
  ok|fail --summary "<sweep summary>"` itself at the end of the run (ok on success, fail +
  re-raise on exception) so the Routines panel at localhost:3737 sees it with no wrapper
  needed. `extract` does not heartbeat separately (it's chained after `sweep` in the same
  cron line; a failed `extract` just leaves `pending_candidates` untouched for next run).

Files in this skill

  • SKILL.md9.8 KB
  • scripts/commitment_ledger.py61.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.