Skip to main content

astern

crowsnest watches the sessions running right now; astern looks back at the wake they left — the transcripts Claude Code already keeps under ~/.claude/projects/. It mines them for what problems recur, where agents get stuck, what one-off code keeps being rewritten, and which words you and your agents don't share, without spending a token twice.

Start here

pip install astern

astern sync                        # read new or changed transcripts, run the free (heuristic) lenses
astern sessions                    # what's synced, newest first
astern show <sid-prefix>           # one session: meta, ledger state, last turns, findings
astern report friction             # (in progress) a lens's findings as a markdown report
astern judge                       # (in progress) run the LLM-judged lenses over what's synced
astern estimate                    # (in progress) token/cost estimate before a judge batch runs

sync, sessions and show are shipped today. report, judge and estimate are being built out by other agents against the same store and ledger; once they land, the one-command loop is astern sync && astern judge && astern report friction.

What it extracts

Each lens asks one question of a session and returns typed, evidence-backed findings — every finding points back at the turn it came from. Method: H = deterministic heuristic, zero tokens; L = LLM-judged, spends subscription tokens via the local claude CLI; H→L = a heuristic shortlist that only the survivors get judged on.

Lens Question Method
stats The shape of a session in numbers — the cost model's own features H
problems What problem was each session solving, and how was it solved? L
recurring Which problems recur, and would a skill or subagent pay for itself? H over L
rewrites What one-off code keeps being rewritten? H→L
friction Where do agents get stuck, and what would remove the obstacle? H→L
jargon-in Which of my phrasings point to an established term I don't use? L
jargon-out Which terms do agents use that I don't? H→L
corrections What did I correct or re-affirm, and which corrections repeat? H→L
prompt-quality Which prompt shapes lead to clean turns, which to flailing ones? H→L
cost Where do the tokens and hours go, by project / task / model? H
timeline What did I work on this week, and what landed? H→L
decisions Which decisions were made, and why? L
claims Where did an agent claim "done" and a later turn show otherwise? H→L
questions What do agents keep asking me, and what did I answer? H→L
tooling Which skills/subagents/MCP tools are used, unused, or missing? H
memory-candidates Which restated facts should become memory, and where does memory drift? H→L
evals Which (prompt, outcome) pairs make a regression test for a skill? H
hygiene Do agents read before they edit, and does that change over time? H
regression Did the harness or model change behaviour? H
adherence Which CLAUDE.md/skill rules are followed, ignored, or fought? L
subagents Which subagent / Workflow spawns paid for themselves? H
effect Did an adopted rule, skill or function reduce the pattern it targeted? H

Session handoffs (Q) are deliberately not a lens here — that's openloops, linked rather than re-derived. The full catalogue, with the signal each lens reads and the sink it feeds, is plan §2 (see "The seams" below).

Never spending a token twice

Every lens run goes through the ledger: one entry per session, keyed on the transcript file's fingerprint (size + mtime) and, per lens, its version and the last turn index it has seen. From that, ledger.plan() picks one of three actions:

  • skip — this lens version already covered every turn that exists in the transcript.
  • incremental — the session grew (it was resumed); only lenses that declare incremental=True get handed just the new turns (from_index onward) plus their own prior findings, and extend rather than redo.
  • full — never analyzed, or analyzed by an older lens version; everything is reprocessed.

A heuristic lens (kind='H') costs nothing, so paying for full on every source change is fine. The ledger earns its keep on the LLM lenses (kind='L'): a resumed session must not pay again for turns it already paid for, and astern sync never re-reads a transcript whose size and mtime it already has on file.

Where things live

The store is dol-backed JSON files under ~/.local/share/astern/ (sessions, turns, findings, ledger, judgments) — override with $ASTERN_DATA_DIR to keep an experiment out of the real store. The transcripts it reads come from ~/.claude by default — override with $ASTERN_HOME to point at a second account or a synced copy of another machine's home. Both are seams: any MutableMapping serves as a store, and homes() takes a single dir, an iterable of dirs, or None.

The seams

Five things in astern are deliberately swappable, each with a strong out-of-the-box default and a named replacement:

Seam v1 default Replacement
home= — which ~/.claude-shaped dirs to read the one ~/.claude a second account, or the server's home over a sync
store= — where records and findings live dol JSON files under ~/.local/share/astern/ any MutableMapping — S3, SQLite, a dict for tests
judge= — the LLM callable for L lenses the local claude CLI, headless, no session persisted aix.prompt_func for API billing; a recorded-replay judge for tests
similar= — how findings group across sessions normalized-string near match ir corpus + embeddings, for real semantic clustering
turns= — the transcript-to-turns fetcher astern's own openloops-backed iterator priv.claude_transcripts.turn_pair_records by injection

What's deliberately not a seam: the lens registry (a module-level dict), report templates, the finding dict shape, and the openloops.egress scrub step on every sink — none of these are meant to vary.

Not in astern

  • Live sessions — that's crowsnest's axis (this minute), not astern's (the wake).
  • Obligation tracking — what's owed, blocked, or open — that's openloops.
  • Transcript viewers, full-text search, cost dashboardsclaude-code-log, cc-transcript, episodic-memory and ccusage already do these well; install them alongside astern rather than rebuilding them here.
  • Writing into CLAUDE.md, skills, or memory. Every lens emits candidates — mined skill/rule/function/memory suggestions — for a human to accept through skill, opsward, coact, or ge.memory. Nothing here writes automatically; that's the same "report, never repair" invariant priv upkeep carries.

Development

pip install -e ".[dev]"
pytest -q                            # the test suite
pytest --doctest-modules astern      # every module's own doctest

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

astern-0.0.2.tar.gz (63.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

astern-0.0.2-py3-none-any.whl (57.8 kB view details)

Uploaded Python 3

File details

Details for the file astern-0.0.2.tar.gz.

File metadata

  • Download URL: astern-0.0.2.tar.gz
  • Upload date:
  • Size: 63.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","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}

File hashes

Hashes for astern-0.0.2.tar.gz
Algorithm Hash digest
SHA256 2a45c261f727dfe7c45b2e748fa2c11d33bb61778e68a9c6a2c0bf3cc8a4e38f
MD5 5b02034fb892aaa72f2b1c0862945225
BLAKE2b-256 634dc331c0c91d0dcab52c784f8a93170322c67c475d17f99b28eb95553e8525

See more details on using hashes here.

File details

Details for the file astern-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: astern-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 57.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","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}

File hashes

Hashes for astern-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 314121e640702dc0ff1ae63a7dfbadc045f05e9e3e7e3e91b7185ad328be74f5
MD5 ad6dbc2598e1505a2daca850476c4829
BLAKE2b-256 2f29638105ef96d6193d13c4ee635f4e79fb53d6962bc63f04044b72064be797

See more details on using hashes here.

Release history Release notifications | RSS feed

0.0.9

2 files

0.0.8

2 files

0.0.7

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

This release

0.0.2 This release

2 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