Skip to main content
Glama

Workbeast

A connector-fed commitment ledger with an MCP tap.

Sources you already use flow in; the people, facts, and open commitments in them are extracted onto a small governed knowledge base; one MCP server serves that knowledge to the LLM you already use; and when a commitment looks finished, closing it is suggested with evidence and confirmed with one tap.

Storage is markdown and YAML in a git repo. No database, no embeddings, no web server, no screen capture, no transcription. The only long-running process is a local MCP server on stdio.

For reviewers — start here

Four commands, no credentials, about three minutes.

npm install
npm test                    # 85 tests
npm run demo                # whole pipeline, temp dir, your disk untouched
npm run demo -- --seed      # populate the KB so you can query it yourself

Needs Node ≥ 20 (node --version) and nothing else — no keys, no network, no Google account.

Then point Claude Desktop at the server (Setup → 6) and ask whatever you like. --seed writes six fixture events, two open loops, a counterparty, and one pending close proposal, so all five tools have something real to act on. npm run demo -- --reset removes them again.

Questions that work, none of them special-cased:

search my memory for the pricing deck · what do you know about Priya? · anything about the Whitefield site survey? · when is the BSB board review? · was an invoice issued? · what am I waiting on? · resolve BSB · resolve BSBX

What to look for, in order of what it demonstrates:

  1. resolve BSBX returns found: false. It refuses to guess an entity that merely resembles a known one — the failure mode that silently corrupts every loop attached to it.

  2. what am I waiting on? shows a pending proposal, not a closed loop. A HIGH-confidence match is deliberately withheld from auto-closing until its category earns it. See Why nothing auto-closes yet.

  3. Ask Claude to read the workbeast agent contract. The governance rules are served as MCP resources, so the model can load and obey them rather than being told about them.

  4. cat kb/logs/decisions.md — every automatic decision ends with reverse:.

Three things that are honestly not finished, detailed in Verification status: live extraction needs a funded Anthropic key (supply your own in .env); the Fireflies mapping has never seen real data; and retrieval is keyword + IDF with no embeddings, so paraphrase without shared vocabulary misses — a deferral the spec makes explicit, with the trigger for lifting it.

Related MCP server: imprint-mcp-server

The two moments this exists to produce

  • "My AI already knows." You ask Claude "what am I waiting on from Priya?" and it answers without you pasting any context.

  • "It noticed I finished." You send the deck; the system observes that event, links it as evidence, and offers to close the open loop.

Layout

Path

What it is

kb/events/

Tier 0, the event log. One YAML file per ingested event. Append-only, gitignored — raw mail and transcript bodies never leave the machine.

kb/rules/entities.yaml

The resolution ledger: canonical ids + aliases. Every counterparty reference resolves to one of these.

kb/rules/authorities.md

Declared systems of record — which source is allowed to assert each fact type. Plus the conflict-block format.

kb/config/freshness.md

Volatility class × staleness cost per fact type, and the resulting verdict.

kb/config/trust.yaml

The trust ladder. Which loop categories may auto-close, and what they must earn first.

kb/canon/facts.md

The small governed list of facts the system may assert. Each carries source, as_of, and stakes.

kb/loops/ledger.yaml

The commitment ledger.

kb/logs/decisions.md

Append-only; every automatic decision with its reversal.

kb/AGENT_CONTRACT.md

The eight clauses every runner loads before a governed run.

config/user.yaml

Who this instance belongs to. The only place identity lives.

Everything under kb/ except events/ is committed. That git history is the audit trail: git log -p kb/loops/ledger.yaml shows every state change a loop has ever undergone.

Setup

Everything below step 2 is only for running against your own live accounts. To evaluate the system, npm run demo needs none of it.

What each credential unlocks

Credential

Without it

Required for

none

tests + npm run demo + all five MCP tools on seeded data

evaluating the design

GOOGLE_CLIENT_ID / _SECRET

no mail or calendar is pulled

live Gmail + Calendar

FIREFLIES_API_KEY

the run reports FAILED and exits 1 — see trip hazards

Fireflies transcripts

ANTHROPIC_API_KEY (funded)

events ingest but no loops are ever created

extraction + matching

DEEPSEEK_API_KEY

--provider deepseek only

Trip hazards

Four things that make a correct setup look broken. Each is real, each has been hit on a working machine.

  1. An unfunded Anthropic key silently costs you events. Ingest is idempotent by event id, and extraction only ever runs over events written that run. So a run made before the key is funded writes events to kb/events/, fails every extraction, and a later run skips those events as already ingested and never extracts from them. The run now prints EXTRACTION DOWN and exits 1 rather than looking like a quiet inbox, but the events are already spent. Confirm the key works before your first real run — see step 5. Recovery is to delete the affected files from kb/events/ and re-run with the same window.

  2. No Fireflies account means every run exits 1. FIREFLIES_API_KEY is read with the same requireEnv as the rest, so an unset key is a connector failure, not an absent connector — Gmail and Calendar succeed and the run still exits non-zero. Harmless to the KB, but it will look like a broken install and it will fail CI. Set any non-empty value to skip it cleanly.

  3. config/user.yaml ships with placeholder addresses, and nothing warns you. It is committed, it contains you@example.com, and no code validates it. Until you put your real addresses there, your address is not recognised as "me" — which is what decides email_sent vs email_received, so every mail you sent is filed as mail you received, and the extraction prompt is told the wrong thing about who the user is. Edit it and the mirrored user entry at the bottom of kb/rules/entities.yaml; the two must agree, and nothing checks that they do.

  4. A solo calendar entry produces nothing, by design. See Verify it yourself → 5.

1. Identity and secrets

cp .env.example .env    # then fill in the keys
$EDITOR config/user.yaml

The user's entry in kb/rules/entities.yaml mirrors config/user.yaml. If you change one, change the other. Both ship with placeholder addresses that nothing validates — see trip hazard 3.

2. Install and verify

Node ≥ 20 is required (package.json engines); the pipeline uses node --input-type=module and Node 20+ APIs, and older versions fail in ways that do not name the cause.

node --version    # must be >= 20
npm install
npm run typecheck
npm test          # expect 85 passed

3. Google OAuth

Create an OAuth client in the Google Cloud Console under APIs & Services → Credentials → Create credentials → OAuth client ID, application type Desktop app. Enable the Gmail API and Google Calendar API for the same project. Copy the client id and secret into .env.

While the consent screen is in Testing mode, add your own address under OAuth consent screen → Test users, or Google refuses with access_denied.

There is no separate login command. The first run that needs Google will bind a loopback listener on an ephemeral port, print an authorisation URL to stderr, wait for you to approve, then cache the token at GOOGLE_TOKEN_PATH (.tokens/google.json, mode 0600, gitignored). Later runs reuse it silently.

Scopes are read-only (gmail.readonly, calendar.readonly). Workbeast never sends, deletes, or modifies anything in your Google account, and the scopes make that enforceable rather than merely intended.

Delete .tokens/google.json to re-authorise; use https://myaccount.google.com/permissions to revoke.

GOOGLE_TOKEN_PATH resolves against WORKBEAST_ROOT (which defaults to the current working directory), not against the process's cwd. Running the pipeline with a different WORKBEAST_ROOT therefore looks for the token under that root, finds none, and reopens the consent flow. Use an absolute path in .env if you run against more than one root.

4. Fireflies

API key from Fireflies → Settings → Developer Settings, into .env.

5. Anthropic

API key from https://console.anthropic.com, into .env. The account needs credits — a Claude.ai Pro or Max subscription does not fund API usage. An unfunded key does not fail at startup; it fails per event, at billing, with 400 … credit balance is too low.

Confirm the key is funded before the first real run, because a run made with a dead key spends events that no later run will reprocess (trip hazard 1):

npm run extract -- --dry-run --since 1d   # pulls, writes nothing

A dry run makes no model calls at all — it stops before extraction — so it proves the connectors and not the key. To prove the key itself, run for real on the narrowest window you can and read the summary: extraction errors 0 is the line that matters. If instead you see EXTRACTION DOWN, fix billing, delete the events that run wrote from kb/events/, and run again.

Reviewing this project? The extraction and matching passes call the Anthropic API, so they need a funded key. Supply your own in .env as ANTHROPIC_API_KEY and run npm run extract -- --since 7d.

To see the pipeline work without any credentials at all, run npm run demo — see below.

Seeing it work with no credentials

npm run demo                # walkthrough in a temp dir — never touches kb/
npm run demo -- --seed      # populate the real kb/ so you can query it
npm run demo -- --reset     # remove every fixture again

npm run demo runs the real pipeline against fixture events with canned model responses, in a throwaway temp directory. It demonstrates, in order: idempotent re-ingest, politeness not being mistaken for a commitment, an unresolvable counterparty being dropped rather than guessed, and a HIGH-confidence match being refused an auto-close because its category sits at suggest-only.

--seed exists because kb/events/ is gitignored — it holds real mail — so a fresh clone has an empty event store and every query returns nothing. Seeding writes six fixture events, a counterparty, two open loops and one pending proposal into the real KB, which is what lets someone who has never connected Gmail exercise all five tools. Every fixture id contains demo, and --reset removes them (the decision log keeps its lines — it is append-only by design).

This is fixture data, clearly labelled as such. It proves the machinery and the governance rules; it does not prove extraction quality on real mail — that is kill criterion 2, and it needs a funded key.

Exercising the real prompts without Anthropic credits

npm run demo -- --provider deepseek     # needs DEEPSEEK_API_KEY in .env

Test-only. The fixed stack is Anthropic; DeepSeek is never the default and is reachable only through this flag. It reuses EXTRACTION_SYSTEM_PROMPT, MATCH_SYSTEM_PROMPT, and both renderers verbatim, so what it says about prompt quality transfers. What it does not exercise is Anthropic structured outputs — DeepSeek has no equivalent, so that path uses JSON mode. A green run here says nothing about the messages.parse code in production.

Running it found two real bugs, which is the whole reason it exists:

  • The model returned due: "2026-08-14T00:00:00.000Z" where the schema's description asked for YYYY-MM-DD. LoopSchema rejects that, and since the ledger is validated whole before writing, one bad date would have rejected the entire run's write. Fixed with normalizeDueDate, applied on both providers — a description in a schema is a request, not a constraint.

  • With a bare entities.yaml, a live model names the person ("Priya") and every loop is correctly dropped as an unknown counterparty. Correct behaviour, and a warning: without the day-one declaration pass this product outputs nothing. Seeding entities is not polish.

6. Claude Desktop

npm run build

Then in claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\):

{
  "mcpServers": {
    "workbeast": {
      "command": "node",
      "args": ["/absolute/path/to/workbeast/dist/mcp/server.js"],
      "env": { "WORKBEAST_ROOT": "/absolute/path/to/workbeast" }
    }
  }
}

Both paths must be absolute, and WORKBEAST_ROOT is required — Claude Desktop launches the server with an arbitrary working directory. Restart afterwards.

7. The day-one declaration pass

One sitting, under an hour, ~10 declarations. Skip this and the governance layer is furniture.

  1. Seed kb/rules/entities.yaml with the aliases you already resolve in your head.

  2. Declare systems of record in kb/rules/authorities.md for the fact types you touch weekly. Money, pricing, and contract terms ship unassigned on purpose — until you declare an authority, the agent refuses to assert them.

  3. Check kb/config/freshness.md against your actual sources.

  4. Write 5–15 facts into kb/canon/facts.md, each with source, as_of, and a stakes tier. Only things you would state as true to someone else.

8. The setup gate

Before trusting any of it: a fresh Claude session, pointed at the KB, must resolve "BSB" correctly and be able to say why. If it can't, the trust layer is not real yet.

Running

npm run extract -- --dry-run          # pull and report, write nothing
npm run extract -- --since 48h        # default window is 24h
npm run extract -- --since 2026-08-01 # or an ISO date

The run follows: pull → ingest → canonicalize → extract → append loops → match → report. Everything it writes carries generated_by: agent, and every state change gets a reversible line in kb/logs/decisions.md.

Re-running is safe — events already in kb/events/ are skipped, so overlapping windows never duplicate. A failing connector is reported and the run continues, exiting non-zero so cron notices. A single event that trips a model refusal or truncation is skipped and counted, not fatal.

Every event failing extraction is treated differently: that is not a run of awkward events, it is the model being unreachable — no credits, a bad key, no network. The run prints EXTRACTION DOWN and exits 1. Without that it would be indistinguishable from a quiet inbox: zero loops, exit 0, cron reporting success while the ledger silently stops growing.

That distinction matters because skipping is not deferral. Extraction runs only over events written that run, so an event ingested during an outage is never revisited. Recovery is manual: delete those files from kb/events/ and re-run the same window.

The run prints at most one question, about the most frequent unresolved name, and never blocks on it.

The five MCP tools

Canonicalization lives inside the tools, so even a contract-less runner gets clean entities back.

Tool

What it does

search_memory

Keyword + recency search over the event log. No embeddings.

get_open_loops

The ledger, filtered by needs-you / waiting-on-them / overdue, plus any pending close proposals.

resolve_entity

Canonical entity for a name or alias, or found: false. Never guesses.

propose_close

Acts on one loop. Default action proposes a close with evidence and changes nothing; confirm is the only action that closes; reject dismisses a proposal; ack / snooze / unsnooze / waiting-on-them record acknowledgments.

log_decision

Appends one reversible line to the decision log.

No tool ever modifies kb/events/.

The governed KB as MCP resources

Tools serve derived answers; resources serve the rules those answers must follow. Without them a runner connected only through this connector could not read the contract it is required to obey, and clause 1 — "load rules/entities.yaml first" — would be impossible to satisfy.

Six read-only resources are published: workbeast://kb/agent-contract, /entities, /authorities, /freshness, /canon, /trust-ladder.

Load the contract first, every session.

Why nothing auto-closes yet

Two signals close a loop: observation (a connector event satisfied the done_means) and acknowledgment (you said so). Both are gated by the trust ladder in kb/config/trust.yaml.

Every category starts at suggest-only, where even a HIGH-confidence match becomes a proposal rather than a close. A category graduates to auto-close only after its measured precision earns it — 20+ proposals at ≥95% — and graduation is a human edit to that file. The system never promotes itself.

This is deliberate: an unearned auto-close that turns out wrong destroys trust in the ledger permanently, and the ledger is the entire asset.

Workbeast marks resolved; it does not execute. Closing a loop updates the ledger. Sending the email is the connected LLM acting on your explicit tap. The machine prepares; the human commits.

Verify it yourself

Six checks, in order. Each says what you should see and what it proves.

1. The code is sound — no credentials needed

npm install && npm run typecheck && npm test

Expect 85 passed. Proves the ledger rules, entity matching, idempotent ingest, decision-log round-tripping, and the trust ladder all behave.

2. The pipeline runs end to end — no credentials needed

npm run demo

Expect 2 loops created, 1 dropped (unknown counterparty), and a HIGH match that is not closed. Proves the whole sequence works and the governance rules fire. Your real kb/ is untouched — it runs in a temp directory.

3. Claude Desktop can reach it

After npm run build and the config in step 6 of Setup, restart Claude Desktop and ask:

resolve BSB

Expect BSB Homes. Then ask resolve BSBX and expect found: false — it must refuse to guess. This is the setup gate from the MVP spec.

4. It pulls your real mail

npm run extract -- --dry-run --since 7d

First run opens a browser for consent. Expect a count of real events and Dry run — nothing written. Proves OAuth and the connectors work.

5. It extracts real commitments

Requires either Anthropic credits, or DEEPSEEK_API_KEY and --provider deepseek.

npm run extract -- --since 2d --provider deepseek

If your inbox is mostly automated mail, expect 0 loops — and that is the correct answer. Verify it is refusing rather than failing: the summary prints extraction errors if calls are failing. No errors plus no loops means it read your mail and declined to invent commitments, which is the behaviour you want.

To see it find something, you need mail that contains a commitment. The honest way to produce that is to send yourself one:

  • from another address, ask for something with a deadline

  • reply from this address delivering it

Then npm run extract -- --since 1h --provider deepseek, having first added the other party to kb/rules/entities.yaml — an unknown counterparty is dropped by design, not guessed.

Calendar needs the same care, and fails a naive test. A calendar entry only becomes a loop if it carries an obligation to someone. CommitmentSchema requires a counterparty, and a loop whose counterparty does not resolve is dropped rather than guessed. So a solo block on your own calendar — no attendees, a title like read pnc or commitment for leetcode — correctly extracts zero commitments no matter how it is worded. That is the system refusing to invent a second party, not the connector failing.

To test the calendar path properly:

  1. Create an event with a real attendee, and put a commitment in the description ("I'll send the revised quote before this call").

  2. Add that attendee to kb/rules/entities.yaml.

  3. npm run extract -- --since 1d --horizon 14d.

Check the pull line first — gcal N event(s) proves the connector; loops are a separate question downstream of it. Note the calendar window looks forward to --horizon (default 14d) while mail looks backward to --since, so an upcoming meeting is in scope and a long-past one is not.

6. Inspect the evidence by hand

Nothing is hidden in a database. Read the files:

cat kb/loops/ledger.yaml        # the commitments
cat kb/logs/decisions.md        # every automatic decision + how to reverse it
ls kb/events | wc -l            # events ingested
git log -p kb/loops/ledger.yaml # every state change a loop ever underwent

Every line in the decision log ends with reverse:. If a loop changed state with no matching line, that is a bug — the two must always agree.

Verification status

Honest accounting of what has and has not been exercised against live services.

Area

Status

MCP server, 5 tools + 6 resources

Verified end-to-end through a real MCP client, and in Claude Desktop

Trust ladder, ledger, decisions, entities, ingest

85 unit tests, all passing

Pipeline composed end-to-end (ingest → canonicalize → extract → append → match → report)

Verified against a temp KB with mocked models

Match routing + suggest-only gate

Verified with a mocked model: HIGH does not close

Freshness verdicts, snooze/unsnooze, measured precision

Verified live over MCP

Fireflies connector

Auth and query verified live against their API; the account holds 0 transcripts, so the transcript→SourceEvent mapping is unproven

Gmail + Calendar connectors

Verified live. OAuth consent completed, token cached and reused; a real pull returns real mail and real calendar events, ingested idempotently

Calendar → loops

Unproven, and not yet testable here: every event on the authorising account is a solo block with no attendees, which correctly yields zero commitments. Needs an event with a real attendee — see Verify it yourself → 5

Extraction + matching, live

Blocked: the Anthropic account has no credits. The request is built and sent correctly; the API rejects it at billing, per event

To finish: add Anthropic credits, then npm run extract -- --since 7d. The Google side is done.

The v0 kill criteria

Grade honestly after two weeks. These, not the test suite, decide whether it works.

#

Question

Pass

1

A fresh Claude session resolves "BSB" and says why

✅ verified

2

Extraction caught the commitments I actually made

≥ 80% of a hand-audited week

3

≥ 1 evidence-based close proposal was correct and I one-tapped it

Yes

4

The morning answer changed what I did that day

≥ 3 days/week

5

The governance tax stayed invisible

≤ 1 question/run

6

I stopped keeping the loop list anywhere else

Honest yes

Criterion 2 is the one that decides whether the product works at all. Fail → the problem is extraction quality; fix that before building any interface.

Deliberately not built

Not building

Trigger that would start it

Screen / mic capture

Connectors measurably miss loops that matter

Embeddings / vector lane

Fuzzy recall visibly fails

Auto-close without confirmation

A category's measured precision earns it

Auto-execution of replies

Drafts near-zero-edit for a month — then send-with-undo

Multi-viewer / company mode

A real second person appears

Desktop app

A capture need the web can't serve

Transcription

Never — a transcript service owns it

The four non-retrofittable fields are already in the schema while still solo: owner and visibility_scope on every record, the append-only event log with provenance, generated_by: agent on everything a run writes, and canonical entity ids on every reference.

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    D
    maintenance
    Enables semantic search and retrieval of personal and team knowledge from connected sources like Slack, Gmail, Google Drive, and Dropbox, with the ability to save new information for future recall.
    Apache 2.0
  • A
    license
    -
    quality
    D
    maintenance
    Enables querying local meeting notes, calendar events, email metadata, and daily digests from Imprint's database via natural language through Claude Desktop and other MCP clients.
    14
    MIT
  • A
    license
    -
    quality
    A
    maintenance
    Enables LLMs to build and explore a cognitive neuroscience-inspired knowledge graph with SQLite, supporting search, graph traversal, temporal sequences, and structured reasoning.
    23
    MIT

View all related MCP servers

Related MCP Connectors

  • Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.

  • Persistent memory and knowledge graphs for AI agents. Hybrid search, context checkpoints, and more.

  • Your company's brain for AI agents. Cited, permission-aware knowledge across every system.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/omarbshah/workbeast'

If you have feedback or need assistance with the MCP directory API, please join our Discord server