Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add commands/marcosnahuel/antigravity-plugin-cc/notebookgit clone --depth 1 https://github.com/MarcosNahuel/antigravity-plugin-ccWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/commands/marcosnahuel/antigravity-plugin-cc/notebook)<a href="https://agentmods.dev/commands/marcosnahuel/antigravity-plugin-cc/notebook"><img src="https://agentmods.dev/badge/commands/marcosnahuel/antigravity-plugin-cc/notebook.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.00101 | $0.05647 |
| Opus 5 | $0.00051 | $0.02823 |
| Sonnet 5 | $0.00020 | $0.01129 |
| Haiku 4.5 | $0.00010 | $0.00565 |
Grade A, and why
notebook scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 5d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 370 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Local replacement for NotebookLM. Given a folder of documents and an objective,
agy reads every document and produces one objective-driven summary per document, plus a
relevance INDEX.md and a cited RESUMEN_MAESTRO.md. The point is to keep Claude's
context cheap: agy does all the document reading; you only read the two small final files.
Raw user request: $ARGUMENTS
Phase 0 — Parse + list + classify + cache (ONE Bash call)
Parse $ARGUMENTS: split on the first |. Left side = folder, right side = objective.
If there is no |, the longest leading token that resolves to an existing directory is the
folder and the rest is the objective. If the folder is missing, ask once: "¿Qué carpeta querés
analizar?" and stop.
Run ONE Bash call (a Python helper). It lists supported files, classifies each as text
(PDF with a real text layer → pre-extract) or vision (scanned/image → agy OCR), and applies an
incremental cache: a document is marked cached (skipped) when its summary already exists AND
its size+mtime AND the objective are unchanged since the last run. The cache key includes a hash of
the objective, so changing the objective re-summarizes everything.
python - "$FOLDER_ABS" "$OUTDIR" "$OBJETIVO" <<'PYEOF'
import sys, os, re, glob, hashlib
import fitz # PyMuPDF
folder, outdir, objetivo = sys.argv[1], sys.argv[2], (sys.argv[3] if len(sys.argv) > 3 else "")
os.makedirs(os.path.join(outdir, "_text"), exist_ok=True)
objhash = hashlib.sha1(objetivo.strip().encode("utf-8")).hexdigest()[:8]
MAXV, CHUNK, GROUP_MAX, CHAR_BUDGET = 20, 15, 4, 24000 # scans >MAXV pages -> CHUNK-page subs; uncached text docs -> groups of <=GROUP_MAX docs and <=CHAR_BUDGET chars (1 agy call -> many summaries)
cache_path = os.path.join(outdir, "_cache.tsv"); prev = {}
if os.path.exists(cache_path):
for ln in open(cache_path, encoding="utf-8"):
pp = ln.rstrip("\n").split("\t")
if len(pp) == 2: prev[pp[0]] = pp[1]
exts = (".pdf",".docx",".doc",".png",".jpg",".jpeg",".webp",".gif")
files = sorted(f for f in glob.glob(os.path.join(folder,"*")) if f.lower().endswith(exts))
def slug(s):
s = re.sub(r"[^a-z0-9]+","-", os.path.splitext(os.path.basename(s))[0].lower()).strip("-")
return s[:60] or "doc"
def mkrow(nn, mode, src, tpath, summ, key): # incremental cache per output file
if os.path.exists(os.path.join(outdir, summ)) and prev.get(summ) == key:
return (nn, "cached", src, "-", summ, key)
return (nn, mode, src, tpath, summ, key)
rows=[]; small=[] # small = UNCACHED text docs to pack into groups: (nn, sl, tpath, srcabs, key, nchars)
for i,f in enumerate(files,1):
nn=f"{i:03d}"; sl=slug(f); st=os.stat(f); key=f"{st.st_size}:{int(st.st_mtime)}:{objhash}"
is_pdf=f.lower().endswith(".pdf"); mode="vision"; tpath="-"; pages=0; d=None; nchars=0
if is_pdf:
try:
d=fitz.open(f); pages=d.page_count; txt="\n".join(p.get_text() for p in d)
if pages and len(txt.strip())/pages >= 200:
mode="text"; nchars=len(txt.strip()); tpath=os.path.join(outdir,"_text",f"{nn}-{sl}.txt")
open(tpath,"w",encoding="utf-8").write(txt)
except Exception:
mode,pages,d="vision",0,None
if mode=="vision" and is_pdf and pages>MAXV and d is not None:
os.makedirs(os.path.join(outdir,"_chunks"),exist_ok=True) # oversized scan -> page-range chunks
for ci,startp in enumerate(range(0,pages,CHUNK),1):
endp=min(startp+CHUNK,pages)
cpath=os.path.join(outdir,"_chunks",f"{nn}-{sl}-p{startp+1:03d}-{endp:03d}.pdf")
sub=fitz.open(); sub.insert_pdf(d,from_page=startp,to_page=endp-1); sub.save(cpath); sub.close()
summ=f"{nn}-{sl}-p{startp+1:03d}-{endp:03d}.resumen.md"
rows.append(mkrow(nn,"vision",cpath,"-",summ,f"{key}:c{ci}"))
elif mode=="text":
summ=f"{nn}-{sl}.resumen.md"
if os.path.exists(os.path.join(outdir,summ)) and prev.get(summ)==key:
rows.append((nn,"cached",os.path.abspath(f),tpath,summ,key)) # already summarized -> skip
else:
small.append((nn, sl, tpath, os.path.abspath(f), key, nchars)) # pack into a group below
else:
rows.append(mkrow(nn,mode,os.path.abspath(f),tpath,f"{nn}-{sl}.resumen.md",key))
if d is not None: d.close()
# greedy-pack UNCACHED text docs into groups (<=GROUP_MAX docs, <=CHAR_BUDGET chars) to cut agy calls.
# Each group = ONE agy call that writes one summary file PER member (see Mode: notebook-group).
batches=[]; cur=[]; cc=0
for it in small: # it = (nn, sl, tpath, srcabs, key, nchars)
if cur and (len(cur)>=GROUP_MAX or cc+it[5]>CHAR_BUDGET):
batches.append(cur); cur=[]; cc=0
cur.append(it); cc+=it[5]
if cur: batches.append(cur)
for gi,b in enumerate(batches,1):
if len(b)==1: # lone text doc -> 1-per-call (no group overhead)
nn,sl,tpath,srcabs,key,_=b[0]
rows.append((nn,"text",srcabs,tpath,f"{nn}-{sl}.resumen.md",key)); continue
g=f"G{gi:02d}"
texts="|".join(x[2] for x in b) # member text paths
names="|".join(f"{x[0]}-{x[1]}" for x in b) # member display names
summs="|".join(f"{x[0]}-{x[1]}.resumen.md" for x in b) # one output file PER member
gkey="|".join(x[4] for x in b) # per-member cache keys (pipe-joined)
rows.append((g,"group",texts,names,summs,gkey))
rows.sort(key=lambda r: r[0])
with open(os.path.join(outdir,"_manifest.tsv"),"w",encoding="utf-8") as m:
for r in rows: m.write("\t".join(r)+"\n")
nc=sum(1 for r in rows if r[1]=="cached"); nt=sum(1 for r in rows if r[1]=="text")
nv=sum(1 for r in rows if r[1]=="vision"); ng=sum(1 for r in rows if r[1]=="group")
print(f"DOCS={len(files)} ROWS={len(rows)} CACHED={nc} TEXT={nt} VISION={nv} GROUPS={ng} OUTDIR={outdir}")
for r in rows: print("\t".join(r))
PYEOF
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 5d ago First seen · 370 lines · 101 tokens per session scan A 07ce679cc867
notebook is a command published in the GitHub repository MarcosNahuel/antigravity-plugin-cc (26 stars, last pushed 19d ago), licensed MIT. It adds 101 tokens to every session and 5,647 once invoked, about $0.0005 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.
Other commands, from other repositories
octo-docs
Document delivery with export to PPTX, DOCX, PDF formats.
paper-trail-inject-url
Injecte une URL OA connue (HAL, dépôt uni, NIME, page perso) pour une ref dont la cascade automatique a échoué, puis relance l'acquisition + validation page 1.
paper-trail-acquire
Troisième passe du pipeline cible refondu. Lance la cascade PDF (10 sources : Crossref OA + arXiv + OpenAlex + Unpaywall + HAL + CORE + éditeur par DOI + archive.org + WebSearch ; jusqu'à 17 avec les voies par navigateur et les sources étendues opt-in) ciblée sur les refs d'un SOTA donné. Différent de pipeline run qui…
paper-trail-cascade
Acquire PDFs via the 8-source cascade (11 with opt-in extended sources) for a single ref by slug, or a batch filtered by state. Validates page 1 anti-homonymy on each download.
docs
Document delivery with export to PPTX, DOCX, PDF formats.
adr-export
Export ADRs to HTML, JSON, or PDF format.