Releases: lazymaniac/hologram
Release list
v0.17.0
Theme: only what cannot be read somewhere already.
Removed
- Constructors. A ctor line stated that a type can be constructed, which its
own header already implies; where its arguments differed from the field list
it stated a construction contract, but never the project's purpose. It cost
4.6% of a 16,000-file Java map, 4.0% of a Java example corpus and 3.8% of a
Spring one — more than all five markers put together — and had no--features
name because it lived in the always-on signature remainder. - The
✓tested marker, and thetestedfact class with it. It discriminated
wildly by corpus — landing on 42% of callable lines in one repository and 1
line in 312 in another — and two thirds of its cost on a large map was the
lossless grouping it prevented rather than the marker's own characters. The
reachability it displayed is still computed and still ranks a tested call path
above every other chain in the budget; it is simply no longer rendered. - Individual test case names.
? testsnow states which files hold tests and
what reusable support they expose, and nothing inside them. Case names were the
single most expensive thing in the map — 34% of a 16,000-file corpus, 78% of
this repository's own — for a fact an agent reads in the file the landmark
already points at. Helper and fixture names stay, because those are what
another test file consumes without opening anything.
Together these take 39.8% off a 16,000-file Java map (56,336 → 33,915
tokens), 12.9% off a Java example corpus, 14.3% off the javamini fixture and
78.2% off this repository's own map.
v0.16.0
Theme: a name says only what the reader's position does not.
Added
--features params. Parameter names were 14–24% of a real map and were
the one large fact class with no name, because they sat in the always-on
"identity" remainder alongside the trie and the type headers. They are a fact
about the code, not the map's structure, so they are selectable now.
Deselecting keeps arity and drops only the names —place(order,items)
becomesplace(_,_), reusing the placeholder the renderer already emits for
an argument no extractor could name — and takes about 7% off a map that keeps
everything else.
Changed
- Grouped landmarks take the declared extension too.
{ItemId,OrderId}.java
now renders{ItemId,OrderId}under a# hologram ·.javaheader, like every
other leaf. They had been exempt so that payload naming files could tell a
reader the bare node above it was a directory — which cost the hoist most of
its value exactly where it pays best, on the one-public-class-per-file
languages whose every landmark is grouped. Worth 3.9% of thejavamini
fixture, 0.7% of a Spring corpus and 0.5% (306 tokens) of a 16,000-file Java
codebase. The reader's rule is now simply that a node with nodes below it is a
directory; a directory whose files are all grouped landmarks reads as a file,
measured at about one node in fifty, and never silently — the reconstructed
path does not exist while the directory does. - Call targets are named relative to the caller. The description ladder
picked the shortest name that is unambiguous across the whole project, which
is the right question to ask once and the wrong one to answer on every line:
a chain insidea/b/Order.javathat read> a/b/Order.java:Order.total
spent 24 characters restating the node the reader was standing in. A target
now carries only what the caller's own path, file and owner do not already
say. Worth 7.9% of a monorepo of near-identical services, 2.4% of a Java
example corpus, and 1.2% — 699 tokens — of a 16,000-file Java codebase. Two
targets that would shorten to the same text both keep their project-wide
names, so one name never stands for two.
Fixed
- Framework-wired code is no longer reported as dead.
×0means no static
project reference, and a container's wiring is invisible to static fan-in, so
Spring stereotypes and@Beanfactories, JSR-330@Named/@Inject,
@PostConstruct/@PreDestroylifecycle callbacks, JPA@Entity, and Spring
AI/MCP@Toolsurfaces now join routes, listeners and schedulers as
entrypoints. On a Spring AI corpus this removed 63 of 113×0markers — a
@Configuration @EnableWebSecurityclass and every@Beanfactory had been
reading as deletable — and made the map 38 tokens smaller in the process.
v0.15.0
Theme: you choose the facts, and the map stops repeating itself.
Added
--featuresselects which fact classes the map carries. A budget decides
how much of the map fits; it could not say what was eligible in the first
place.
Twelve named classes (calls,relations,fields,constants,
decorators,raises,tested,usage,size,private,tests,
support) can now be dropped whole, withtypesmaking thirteen. Gating
happens at each render site before the budget catalog, so a deselected class
never enters the adaptive search and cannot be restored by it. The package
trie, type headers, and public signatures are the map's identity and stay
unselectable;--features noneleaves exactly those. The selection is stamped
in the footer and recalled like--langand--budget, and--interactive
onbuild/initprices a selection against the full map before writing it.--features types. Declared return and parameter types are now a
selectable fact class, closing a gap between the feature catalog and the
structure floor: L8 already stripped them, but nothing named them. They cost
1.0% of this repository's map, 2.8% of a TypeScript corpus and 5.1% of a Java
one — more than seven of the twelve classes that were already selectable.- L8, a structure-only floor below the semantic floor. When even L7 cannot fit a
--budget, Hologram now renders the same facts in project vocabulary alone: return
and parameter types, decorators and route paths,!throws,~N/✓/×0markers,
{field}lists, and: super/←impls/sealed:relations all go, leaving the
source tree, type names, and function names with their parameter names. On this
repository the floor drops from 714 to 460 tokens. Ranked whole facts still compete
for slack above it, and the previous "no complete map fits" fallback now runs only
when L8 overflows too.BudgetStats.skeleton_tokenskeeps meaning the L7 semantic
floor;effective_detailreportsL8orL8-adaptive:n/m.
Changed
- The extension a map repeats is declared once. A title line such as
# hologram ·.pystates the corpus extension, and the file nodes that carry
it render bare; a leaf that states an extension has exactly the one it
states. Worth 1.2–1.5% of a real map (57 tokens on a 4,936-token TypeScript
corpus, 95 on a 6,220-token Java one) and nothing where it would not pay: a
stem another node already owns (extract/besideextract.py), a stem still
holding a dot (shell.component), and corpora too small or too mixed to earn
the declaration all keep their extensions. Grouped landmarks
({ItemId,OrderId}.java(R{value})) keep theirs too, which is what tells a
reader the bare node above them is a directory. - The test index states landmarks and support, never call targets. The
> target +Ncoverage edge is gone: it spent tokens naming one arbitrary
target and counting the rest, and what a test file exercises is already
legible from the case names it carries.? testsnow holds exactly test
classes, test functions and methods, helper classes, helper functions, and
declared fixtures. - Fixtures and shared helper functions are named. A fixture qualifies by
declaration (@pytest.fixture,@BeforeEach,@Rule, …) because the
framework injects it by name rather than calling it; a plain function has to
be used by another test file. Teardown markers earn no name. Both render in
the existing*group, whose legend clause is now*=helper/fixture.
v0.14.0
Theme: the map states what it costs.
Added
- The footer carries the corpus and map token counts.
· 19,311 LOC · input 215,433 · output 5,999 tokens · state … · budget …—
inputis the estimated token count of the scanned sources,outputthe
estimated count of the map itself. The block is always loaded, so what it costs
and what reading the sources instead would cost now travel with it.outputis
measured on text that containsoutput, so the render iterates the footer to a
fixed point; where a token boundary makes two candidates alternate, the larger is
stated — the map never claims to be cheaper than it is.
render_simple gained an optional source_tokens parameter alongside loc,
precomputable by callers and computed locally when omitted. Freshness and settings
readers are unchanged: LOC stays the footer's first field, which is how the
metadata line is located, and legacy metadata-bearing headers still parse.
The new fields cost nine tokens per map, flat.
v0.13.0
Theme: the floor is business logic only.
Changed
- The semantic floor drops the test index entirely. At the deepest budget level
the? testssection is absent — header, file landmarks, helper names, and
test-to-business edges alike. Test file landmarks used to be unconditional floor
content, so the tightest budgets paid for test orientation before business API. - Test file landmarks are now individually restorable facts (
test-files), ranked
and admitted like any other optional fact above the floor. Admitting a suite/case
label or a coverage edge also admits the landmark line it renders on, so a restored
name never arrives without the file it belongs to.
Nothing changes for unlimited maps or for budgets that comfortably fit the index; the
difference appears only when a budget binds. On this repository the floor drops from
759 to 701 estimated tokens; corpora with hundreds of test files recover far more,
since the index is proportional to the test tree.
hologram stats reports the new test-files category alongside the existing ones —
the schema grows additively.
v0.12.0
Theme: the test index costs what it is worth.
Changed
? testsrenders through the same path-compressed trie as the source section.
Test files used to carry their whole relative path on every line, so a deep package
tree restated one prefix hundreds of times. Directories are now stated once and the
file landmark sits under them.- Wrapped case names no longer pad to the length of their path. Continuation lines
indent one level instead of aligning under an eighty-character prefix, which on a
deep tree made the section half whitespace.
Both are representation changes: file landmarks, suite names, case names, helper
names, and test-to-business edges are byte-for-byte what they were, and the source
section is unchanged. On a 114k-LOC Java corpus with 293 test files the ? tests
section drops 56% (140,913 to 61,788 characters) and the whole map goes from about
60,600 to about 40,900 estimated tokens. Repos whose tests sit in one shallow
directory see little change.
v0.11.0
Theme: more business-logic signal per always-loaded token.
Added
- Semantic whole-fact budgeting v2. Optional facts now compete globally above a
compact pushed floor. Tested and cross-file call paths, test-to-business edges,
high-fan-in APIs, and breadth across source files outrank local private leaves.
Method-call facts retain their owning method as a dependency, and every admission is
still checked by rendering the complete digest against the hard digest ceiling. - Managed-context accounting. CLI output,
stats/stats --json, and benchmark
rows distinguish digest, wrapper, coaching, and total managed-block estimates. This
keeps the historical digest budget contract while exposing the full context cost an
agent actually receives. - Inspectable selection reasons. Budget statistics add deterministic retained and
dropped reason counts while preserving existing fields additively.
Changed
- Production landmarks now resolve to exact files. Conventional one-type files retain
lossless cross-file shape grouping ({A,B}.java(...)), while multi-entity modules
use explicit file nodes. - Repeated names are factored in signatures, fields, relationships, re-exports, and
call targets only when the notation is shorter. A private inventory entry is omitted
only when the same exact target remains visible in a selected call chain. - Tests retain one actionable landmark per file plus compact coverage/helper hints.
Every recognized test function/method name and suite is shown by default to
discourage duplicate coverage. Names are factored losslessly, same-named methods in
different suites gain their suite owner, and every additional nonredundant label
remains individually droppable when a tight budget needs to preserve business logic
first. Roottoolsandbenchmarkcode gets separate compact orientation instead of
competing with business internals. - Volatile LOC, freshness state, filters, targets, and budget metadata moved to the
final digest line. Existing header-form maps remain readable, while unchanged
semantic prefixes can now be reused by prompt caches. - The fixed embedding note and budget omission warning are shorter and make no claim
that an optional fact survived selection.
Validation
- On Hologram's own test-heavy repository, retaining all 633 recognized case/suite
names raises the deterministic full estimate from v0.10's 3,621 to about 8,260
digest tokens and from 3,769 to about 8,370 managed-context tokens. This is an
explicit duplicate-avoidance tradeoff; the compact floor still falls from about
1,444 to about 760, and explicit budgets can drop every additional test-name label
independently while keeping file landmarks. Full-grammar fixture estimates remain
below v0.10 managed-context baselines. These are representation measurements, not a
claim of improved model outcomes; the earlier matched evaluation predates this
test-inventory change.
v0.10.0
Theme: make token choices and effectiveness experiments inspectable.
Added
- Adaptive whole-fact budgeting. After the least-degraded complete L0–L7
map fits, Hologram deterministically restores individual facts from the next
quality boundary. Every trial measures the complete output, facts remain
indivisible, the entrypoint skeleton stays mandatory, and a fixed trial
bound keeps hook latency predictable. Adaptive headers useA<level>and
structured stats identify the exact selection. hologram stats [--json]reports the budget policy version, selected,
full, and skeleton token estimates, fit/utilization against the deterministic
characters-per-four estimator, effective detail,
and retained/dropped fact bundles without modifying a context file.- Structured review findings.
hologram review --jsonemits stable finding
IDs plus check, kind, subject, path, and detail. The Python API can compare a
baseline and final review asseen,attempted, orresolved; normal human
review output remains unchanged. API drift now preserves overload sets and
covers public kind, signature, field, relationship, mapped decorator/route,
throw, constructor, and constant-value changes. - Resumable benchmark blocks. Schema-v3 results identify the immutable
experiment, treatment/control pair, cell, task, judge configuration, corpus, tool, and
runner mode.--resumeskips only when every planned cell in a task/repetition
block is terminal, evidence-intact, and from the same wave/model; otherwise it
reruns the whole block. Failed attempts remain append-only evidence. Referenced
stdout and stderr artifacts are fsynced, sized, hashed, and verified before a
block can satisfy resume.
Changed
- Benchmark condition order is seeded and counterbalanced. Reports compare
every selected treatment (A,AC, orAR) withBon matched
task/repetition pairs, list incomplete pairs, summarize numeric fields
with median ± MAD, and keep fresh, cache-created, and cache-read input tokens
separate. Structuralaccept_cmdevidence is labelled as such; tasks can
carrymanual_onlyand versioned judge metadata. - Eligible AR rows capture sanitized finding IDs during the existing
post-commit review pass, compare their deduplicated union with the final
working tree, and report resolved, persisting, and new-final counts. This is
an identity-based final-state measure, not a correctness or attempted-action
claim; finding content and IDs never enter the aggregate report. - Real benchmark sessions require
--allow-unsafe-host, an explicit
acknowledgement that the agent runner is not a filesystem, credential,
process, or network sandbox. Dry and real cells cannot share resume IDs. - Acceptance commands declare disjoint pass/fail exit codes; undeclared exits
are judge infrastructure errors. Provider terminal events must satisfy the
metrics protocol, dry runs execute no acceptance shell, unknown task fields
fail before spending, and repeated global or same-condition infrastructure
failures open a circuit breaker.
Security
- Release preparation audits index blobs and non-ignored working-tree files
separately, plus built archives, against private-only paths and an optional
external denylist.
Release-artifact publication remains hard-disabled until repository-history remediation
and a clean-clone privacy audit are complete.
Validation
- Adaptive selection, structured review schemas, exact resume compatibility,
atomic result persistence, matched reporting, parser completeness, and the
release privacy gate have synthetic/public-only regression coverage. This
release makes no unmeasured claim that a prompt or hook timing improves agent
behavior.
v0.9.0
Theme: clever token budgeting. --budget maps are unchanged at L0 — this
release only changes what happens under pressure. Unbudgeted maps are
byte-identical to 0.8.0 (verified on three corpora, modulo the state
stamp).
Added
- Makefile support —
Makefile/makefile/GNUmakefile/*.mkrender
as one node with each target as a command carrying its caller-settable
variables:deploy(ENV,MANIFEST)means the recipe consumes$(ENV)
(overridable?=or undefined) and$(MANIFEST); variables the file
pins with=/:=are internal and excluded..PHONYand friends,
pattern rules, anddefinebodies are skipped;_nametargets are
private. No parser dependency — a line scanner, like Helm.
Changed
- The degradation ladder is repaired and deepened to a skeleton floor.
The old ladder was lumpy (one level dropped −1,921 tokens on the
reference corpus while another dropped −116), partly broken (the private
wipe left per-class- namelines at every level), and shallow (floor
−17%; an 8k budget was unreachable). The new ladder (measured per-level
on the reference corpus): L1 coverage edges (−5%), L2 helper signatures
(−8%), L3 all private inventories (−8%, bug fixed), L4 chains of
untested functions (−6%, replaces the no-op), L5 methods of types with
zero real fan-in (−3%, replaces the name-keyed heuristic), L6 all chains
(−4%), L7 the skeleton — no method lines, const values gone, type
headers with fields and top-level signatures stay (−21%). Floor on the
reference corpus: 7,138 tokens, −54% from the full map. Every level
is monotone; facts degrade in usefulness order; the legend only explains
what survived; nothing is ever cut mid-fact. - Const values survive to the skeleton, and degraded maps disclose
their losses. The first gate round dropped const values at L1 — the
smallest saving (−0.3%) — and produced the worst failure: agents
confidently answered value questions off a map that silently omitted
the values. Now scalars ride to L7, and every degraded map carries a
header disclosure naming the dropped fact classes with an instruction
to read the source instead of guessing — measured to flip wrong
zero-read route answers into correct one-read answers. - The budget ladder no longer re-reads every source file per level
(level-invariant work — LOC count, call resolution, helper detection —
is computed once).
Dev
- Benchmark task files accept a top-level
budget, applied to the
map-bearing conditions' build.
Gates (measured before merge)
- Determinism, monotonicity, floor reachability: pass (numbers above).
- Refactor invariance: unbudgeted digests identical to v0.8.0 on the
reference corpus, this repo, and the polyglot fixtures. - Navigation at the skeleton floor: see benchmark/README.md.
v0.8.0
Theme: cheaper without being smaller. Every change was built behind a
measured merge gate (see benchmark/README.md); one feature — pre-commit
review timing — was built, measured, and reverted for showing no
behavioral gain.
Changed
- Token diet, same facts — three same-fact-twice redundancies removed
(reference corpus −3.7%, self −0.7%, zero information loss):
constructors whose argument list restates the type header's field list
(PricingEngine(basePrices)underPricingEngine(C{basePrices})) are
suppressed, including the groupedSelf(fields)form — any constructor
carrying notes, ✓, sizes, throws, calls, or typed args stays; dunder
methods (__init__,__repr__) leave the private inventories;
the test index folds a file whose only test class matches its name
(PricingEngineTest>applyDelta+2, no braces) and states a shared file
extension once in the header (? tests ·.java). - The
· depsblock is gone. It was a coarser restatement of the call
chains, degenerated on shallow repos, and outlived richer facts under
--budget. Gate evidence: all navigation/architecture answers stayed
correct at 1 turn without it. - Coaching sentence now says what to do with review findings (reuse
the named original, consolidate re-covered tests) instead of just naming
the command.
Measured and reverted
- Pre-commit review timing. Review was moved to a pre-commit hook so
findings would land before the commit; the gate round showed the
reviewer firing identically — and, at low effort, agents acting on the
findings exactly as often as post-commit: never. The post-commit form
ships unchanged; the newacted_on_findingsbench metric stays for 0.9.
Dev
- Benchmark:
acted_on_findingstranscript metric (review report →
later edit of a file the findings named → later commit).