Added
-
One unified "human decisions needed" list —
athenaeum decisions+
athenaeum merges+list_pending_decisionsMCP tool (#401). Athenaeum
accumulated two separate human-decision queues — pending questions
(contradiction detector) and pending merges (resolver proposals) — but
merges had no CLI and appeared in no briefing, so a real backlog (34
proposals aged 1–4 weeks, found 2026-07-20) could sit unseen indefinitely.- New
athenaeum decisions {list,next,count} --jsonreturns both queues
in one call, each item taggedtype: "question" | "merge"with common
fields (id,created_at,summary,confidence) plus a type-specific
payload, sorted oldest-first.countprints
N decisions pending (Q questions, M merges; oldest Xd). - New
athenaeum merges {list,next,count} --json— the merges half, a mirror
ofathenaeum questions(the CLI-only briefing path had no way to read
merges before). - New
list_pending_decisions()MCP tool gives containerized agents the same
unified list. - Every merge is rendered as an answerable question: each source page
is named by its human title (frontmattername:, not the uuid-slug) with a
one-line gist, because cosine topic-similarity alone is not "should-merge"
and misleads without the pages' own words. A human can decide approve/reject
from onedecisions listitem without opening the raw wiki files.
- New
-
Kill switch —
athenaeum disable/enable/status(#379). One
discoverable, reversible command stops all athenaeum background work instead
of hand-editing the hook commands out of~/.claude/settings.jsonand
pkill-ing in-flight detectors. Backed by a state file
($ATHENAEUM_CACHE_DIR/disabled, default~/.cache/athenaeum/disabled) plus
anATHENAEUM_DISABLEDenv override that every entry point honours — the
session-endcompile pass, the MCP write tools (remember,
resolve_question,resolve_merge), and the shell hooks in
examples/claude-code/(which read the file directly withgrep, so the
per-turn recall path adds no Python startup).athenaeum disableturns everything off (compile, contradiction detection,
recall, notifications).athenaeum disable --compileis granular — it stops
only the expensive compile/detect pass and leaves recall on.athenaeum enableremoves the state file and restores prior behaviour
exactly.athenaeum statusnow reports the on/off state, scope, and reason.- The env override wins over the file;
ATHENAEUM_DISABLED=1(orall/
compile) forces the state without touching the file — handy for a scoped
one-off — andathenaeum enablewarns when the env is still forcing it off.
-
Durable LLM-spend ledger +
athenaeum spend+ a spend ceiling (#378).
Athenaeum runs on two cost models that must never be blended — the
claude-clisubscription path (no invoice; consumes subscription quota,
constrained in TOKENS) and the meteredanthropicAPI path (real
dollars: the resolver on the api backend, batch mode, and the per-turn
query-topicsrecall extractor). The in-memory token summary was logged and
discarded, so "how much has athenaeum spent, and is any of it real money?"
was unanswerable from data. Now:- Ledger. Each pipeline run appends one JSONL record to
~/.cache/athenaeum/spend.jsonlcarrying the provider (claude-cli
vsanthropic— the field that makes "are we spending real money?" an
empirical question), run type, model ids, the four token counters kept
separate, and a provider-tagged USD estimate that is always$0on
the subscription path so subscription rows can never be summed into the
dollar total. Append-only and crash-safe (singleO_APPENDwrite per
record; the reader tolerates a torn trailing line); records only counts and
metadata, never content or credentials. On by default; disable with
spend.ledger_enabled: false/ATHENAEUM_SPEND_LEDGER_ENABLED=0. athenaeum spend --since 7d [--by-model] [--by-provider] [--json].
Reports $ for the API path and tokens for the subscription path,
never blended.--jsonis the shape/good-morningconsumes.- Spend ceiling. Configurable per-run and per-day ceilings —
spend.max_tokens_per_run/spend.max_tokens_per_day(subscription
tokens) andspend.max_usd_per_run/spend.max_usd_per_day(API
dollars). On breach the librarian pass stops early and loudly and defers
the remaining intake (like themax_api_callsbudget) rather than silently
continuing. Off unless configured.
- Ledger. Each pipeline run appends one JSONL record to
-
Configurable pre-run pull to sync the knowledge repo (#399).
athenaeum runcan now pull the knowledge repo before a run and push intake + outcomes
after, so a run starts from and lands back to GitHub instead of drifting from
the remote. -
Progress heartbeat for the merge + post-compile phases (#398). Both
phases now emit periodic progress lines, so a long-running (or wedged) run is
legible instead of logging zero output for hours.
Fixed
- Move-then-retire no longer leaves dangling
MEMORY.mdpointers (#388).
The move-then-retire pass (retire.py)git rm'd a retired raw member but
never rewrote the sibling per-scopeMEMORY.mdindex that pointed at it, so
every retirement left a dangling pointer — and unlike the compiled wiki page,
MEMORY.mdloads into every session's context, so a stale line keeps
asserting a fact whose file is gone. The retire pass now drops each retired
member's index pointer in the SAME commit as the deletion (conservative: only
pointers to members that run retired; a pre-existing dangling pointer is left
for the backfill), so index and deletion stay atomic. Cross-tree links
(../wiki/…), URLs, anchors, headings and prose are preserved verbatim.- Backfill:
athenaeum auto-memory prune-index(#388). A one-shot sweep
for pointers already orphaned by pre-#388 runs — dry-run by default (prints
the dangling-per-scope list, exit 2),--applyrewrites the affected
indexes in one labeled, git-recoverable commit. A pointer is dangling when
its bare<file>.mdtarget no longer exists in the scope directory.
- Backfill:
- Stale pre-#330 docstrings in
cli.py(#378 drive-by)._cmd_ingest_answers
and_cmd_reresolve_questionsdescribed "builds a live Anthropic client from
ANTHROPIC_API_KEY"; both now build through the provider seam
(build_llm_client), matching the actual post-#330 behavior. - Resolver over-cluster merges are capped and floored (#400). Degenerate
merge proposals (thousands of sources at low confidence, re-proposed and
regenerated every run) are now suppressed by a cohesion floor plus a size cap. athenaeum runnow has a wall-clock deadline (#396). A hung
post-checkpoint phase can no longer wedge a run indefinitely while holding the
run-lock; the run aborts at the deadline instead.- Runlock auto-recovers an alive-but-wedged holder (#397). A stuck lock
holder is now detected and recovered automatically instead of blocking every
writer until a manual--force. _pending_merges.mdno longer regrows unbounded (#394). Fixes a
regression of #299/#303 that let the file balloon (to ~13MB) and flood each
run with tens of thousands of malformed-header warnings.- Keyword-backend scoring uses term frequency, not presence (#384).
Corrects the keyword search backend's scoring, fixing a Python 3.13 CI flake.
Security
- Workflow hardening for OpenSSF Scorecard (#405). Added a least-privilege
top-levelpermissions: { contents: read }block toci.yml(closes the
Token-Permissions / High alert) and SHA-pinned the remaining tag-referenced
third-party actions —dependabot/fetch-metadata,1password/load-secrets-action,
actions/checkout+actions/create-github-app-token(inpromote-main.yml),
andpypa/gh-action-pypi-publish— each with a trailing# vX.Y.Zcomment,
matching the existing convention.dependabot.yml'sgithub-actionsecosystem
block keeps the pins fresh automatically.