ascent-research 0.4.2

ascent-research — an incremental research workflow CLI for AI agents. Every session resumes; knowledge accretes across runs. Mixes HTTP, browser, and local file ingest into a durable per-session wiki + figure-rich HTML report.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# ascent-research

[![Crates.io](https://img.shields.io/crates/v/ascent-research.svg)](https://crates.io/crates/ascent-research)
[![GitHub Release](https://img.shields.io/github/v/release/actionbook/ascent-research)](https://github.com/actionbook/ascent-research/releases)

> **Your agent's next step up. Every session picks up where you left off. Every turn goes higher.**

**One-line pitch.** `ascent-research` is an incremental research workflow CLI for AI agents: point it at a topic / source tree / Obsidian vault, and it will *keep* researching across sessions — fetching, citing, diagramming, and accreting a durable wiki you can come back to tomorrow and pick up exactly where you stopped.

```bash
ascent-research new "tokio internals 2026" --slug tokio --preset tech
ascent-research add-local ~/tokio/tokio/src/runtime --glob '**/*.rs'
ascent-research loop tokio --provider claude --iterations 12
ascent-research finish tokio --open           # coverage -> HTML -> audit
# (next day)
ascent-research resume tokio && ascent-research loop tokio --iterations 8
```

Bookmark-ready: every session lives as plain files under
`~/.actionbook/ascent-research/<slug>/`, so Obsidian, VS Code, `grep`
and `git` all work.

## Author's positioning — an external handle for agent self-evolution

A Claude Code or Codex conversation ends. The agent forgets everything.
Next week you ask the same question — same search, same fetches, same
half-formed understanding.

I built `ascent-research` because I want my AI agents to **get smarter
over time, not reset every session**. The on-disk session (`session.md`,
`session.jsonl`, `wiki/`, `SCHEMA.md`) is the agent's external long-term
memory — survives process death, carries across tool switches, inspectable
and editable by the human. Every `loop` run isn't "research this topic
from scratch"; it's "continue the research we were doing, check what's
unused from last time, append to the pages you've already written."

The agent-facing surface (actions like `write_wiki_page`,
`append_wiki_page`, `digest_source`) exists specifically so the agent can
*accrete* rather than *overwrite*. The infra-enforced rules
(smell test, preserve_diagram_refs, figure-rich contract) exist so this
long-term memory stays clean without human QA every turn.

Whether you use it standalone or as a skill inside a coding-agent
instance, the pitch is the same: **stop throwing away your agent's
research work at the end of every conversation.** Keep it on disk. Let
the next turn stand on the last one's shoulders.

## Two ways to use it

`ascent-research` is a CLI that calls an LLM provider (Claude via
`cc-sdk`, Codex via `codex app-server`, or `fake` for tests). Which
process hosts the agent decides the usage shape:

### Standalone — ascent-research runs its own loop

Run the CLI directly; it spawns the provider itself and drives the
research loop end-to-end, no outer agent needed. Good for
batch / CI / "I just want a report."

```bash
ascent-research new "tokio internals" --slug tokio
ascent-research add-local ~/tokio/tokio/src
ascent-research loop tokio --provider claude --iterations 12
ascent-research finish tokio --open
```

### Skill — driven from a Claude Code or Codex instance

Drop the bundled skill into your Claude Code / Codex config and the
outer agent invokes the CLI per-turn as a tool. Good for interactive
sessions where you want to mix research with coding / writing work
in the same conversation, or want the outer agent to plan the
workflow (decide what to ingest, when to query, when to synthesize).

```bash
ln -s "$PWD/skills/ascent-research" ~/.claude/skills/ascent-research
# Then in a Claude Code session: /skill:ascent-research
# Or just describe the task — "research tokio's scheduler via source" —
# the skill triggers automatically.
```

Both modes share the same on-disk session format, so you can start
a session in standalone mode and later resume it from inside a
Claude Code / Codex instance, or vice versa.

---

## What's new in 0.4.2

- **Third LLM provider: OpenCode Go** ($10/mo subscription, OpenAI-
  and Anthropic-compatible HTTP endpoints to DeepSeek / Kimi / GLM /
  Qwen / MiniMax). Build with `--features provider-opencode-go`, set
  `OPENCODE_API_KEY` + `ASR_OPENCODE_MODEL`, then
  `ascent-research loop <slug> --provider opencode-go`.
- Useful when Claude Code Pro / ChatGPT Plus subscriptions are out of
  reach (cost or payment-region constraints). All knobs are env-driven
  (`ASR_OPENCODE_PROTOCOL`, `ASR_OPENCODE_TEMPERATURE`,
  `ASR_OPENCODE_MAX_TOKENS`, `ASR_OPENCODE_TIMEOUT_MS`).
- Also works as `ASR_BILINGUAL_PROVIDER=opencode-go` for
  `synthesize --bilingual` Chinese translation.
- **CLI defaults unchanged**`--provider` still defaults to `fake`;
  opt in to `opencode-go` explicitly.
- Thanks to [@Paul-Yuchao-Dong]https://github.com/Paul-Yuchao-Dong
  for raising the use case and contributing the initial design (PR #19).

See `CHANGELOG.md` for the full design rationale incl. what was
deliberately not adopted from the PR.

---

## What's new in 0.4.1

- **x.com / twitter.com tweet capture works end-to-end** through the V2
  browser backend. v0.4.0's generic runcode JS returned ~160 bytes of
  X's left-nav chrome only; 0.4.1 adds an `XTweet` runcode flavor that
  waits for `article[data-testid="tweet"]` (not `networkidle`), scrolls
  with **snapshot-collect across virtualized DOM** so the main tweet
  isn't unmounted out of the result, and reads up to 25 thread articles
  with image / video poster URLs inlined as markdown `![](url)`.
- **3 new tech preset rules**: `x-tweet-status`, `x-profile`,
  `x-search-live` — explicit kinds for `route` debugging.
- **Bugfix in `md_parser::extract_http_links`**: markdown image syntax
  `![alt](url)` is now correctly excluded from the cited-sources scan,
  so embedding pictures of cited tweets no longer trips
  `sources_hallucinated`.

Live impact (same URLs, before vs after):

| URL | 0.4.0 | 0.4.1 |
|---|---|---|
| `x.com/<user>/status/<id>` (any) | 162 B chrome | **2-3 KB** main tweet + thread + media |

See `CHANGELOG.md` for full notes and `specs/x-com-tweet-runcode-flavor.spec.md`
for the design (33 BDD scenarios, lint 100%).

---

## What's new in 0.4.0

- **V2 Actionbook MCP backend is now the default** for browser-rendered
  fetches (Cloud Worker at `edge.actionbook.dev/mcp` + Chrome extension
  over WSS). Set `ACTIONBOOK_BACKEND=v1-cli` to keep the old local-CLI
  path — it's a **permanent fallback**, not slated for removal.
- **Catalog seed pre-fetch**: every `add` / `batch` first probes the V2
  catalog and seeds matching actions into the session wiki, so the
  agent knows what's known about a site before navigating.
- **Composite source fetch**: one rule can fan out into N parts
  (e.g. postagent metadata + browser rendered) merged under
  `composite-v1`; short-circuits on first part failure with a labelled
  `composite_failed_part` event.
- **3 new autoresearch actions** for the loop: `actionbook_search`,
  `actionbook_manual`, `actionbook_run_code`.
- **New flags** on `add` / `batch`: `--frame-id`, `--run-code-args`,
  `--reseed`, `--actionbook-backend`.
- **Default per-source timeout** raised from 30 s → 90 s (V2 server's
  inner run-code budget is 60 s; extra 30 s covers edge overhead).
- Fixes: smell `www.` ↔ apex equivalence; CJK / UTF-8 docs now pass the
  `add-local` text detector; user `--timeout > 60s` is no longer
  silently truncated by the V2 server's hard cap.

See `CHANGELOG.md` for the full list and `docs/rfc/v2-session-export-to-postagent.md`
for the cross-tool RFC that didn't ship in this release.

---

## Why it's different

Five properties — each validated end-to-end across four live research
sessions (tokio internals, an Obsidian agent-SE series, a mixed
online-plus-local AI coding agents comparison, and self-research on
this repo):

### 0. Autoresearch lineage — 2-file resume, extended to reports

Inherits the core loop architecture from
[karpathy/autoresearch](https://github.com/karpathy/autoresearch)
and [pi-autoresearch](https://github.com/davebcn87/pi-autoresearch):
a fresh agent can resume any session from two files —
`session.md` (human-readable living doc) + `session.jsonl`
(append-only event log) — even after process death, context reset,
or a week of inactivity. Where the original autoresearch optimizes a
single scalar (training loss, bundle size, test speed) via
`edit → benchmark → keep-or-revert`, `ascent-research` generalizes
the same loop grammar to *research*:
`plan → fetch → digest → write_section / write_wiki_page / write_diagram`
producing a figure-rich report plus a durable cross-session wiki
instead of a single optimized number.

### 1. Incremental research — sessions resume, knowledge accretes

`ascent-research resume <slug>` picks up exactly where a prior turn
stopped. Wiki pages *accrue* via `append_wiki_page` — new findings
grow existing entity pages instead of overwriting them. Coverage
signals (`sources_unused`, `diagrams_referenced`, `wiki_pages`,
`wiki_total_bytes`) let each loop run know *what's still open* from
the previous turn, so it continues rather than restarts. One-shot
DR tools can't do this — when they finish, they're done.

### 2. Three-way ingest, one pipeline

`add` (HTTP via `postagent`) + `add-local` (file trees) + browser
fallback (via `actionbook browser` for JS-heavy pages) all flow
through the same smell-test → event-log → wiki → report path. A
single session can cite GitHub READMEs, arXiv papers, blog posts,
and your private Obsidian notes side-by-side in one wiki page's
sources list — the renderer doesn't care about URL scheme.

### 3. Figure-rich by contract

Narrative-only output is considered incomplete. The loop's system
prompt carries a non-negotiable FIGURE-RICH CONTRACT: target ≥ 1
hand-drawn SVG per numbered section, bidirectional rule that every
`![](diagrams/x.svg)` markdown reference must have a matching
`write_diagram` action and vice versa, infra-level guarantee that
section overwrites never drop figures. Every SVG is inline
(no external assets, no screenshots) and the HTML report has a
clickable wiki TOC + EN/ZH bilingual toggle.

### 4. Infra-enforced correctness + machine-readable errors

Agents can't "just summarize this for me." Every fetch runs through
a smell test at the CLI layer before the LLM sees it; rejections
become typed events. Overwrites preserve figures. Wiki writes are
append-safe. Coverage computes `sources_hallucinated` (URLs cited
but never fetched) as a `report_ready` blocker. Every error returns
a machine-readable code (`NO_ACTIVE_SESSION`, `SMELL_REJECTED`,
`DIAGRAM_OUT_OF_BOUNDS`, `WIKI_EMPTY`, …) so agents route recovery
deterministically without parsing prose.

---

## Install

```bash
git clone https://github.com/actionbook/ascent-research
cd ascent-research

# Full build (loop + Claude provider) — what live sessions need
cargo build -p ascent-research --release --features "autoresearch provider-claude provider-codex"

export PATH="$PWD/target/release:$PATH"
ascent-research --help
```

Alternative feature sets:

```bash
# Minimal — no autonomous loop, no LLM
cargo build -p ascent-research --release

# Loop with fake provider only (for scripted tests)
cargo build -p ascent-research --release --features autoresearch

# Loop with Codex instead of Claude
cargo build -p ascent-research --release --features "autoresearch provider-codex"
```

Prereqs for online ingest: Rust stable (edition 2024),
[`postagent`](https://github.com/actionbook/postagent) for HTTP API fetches,
and (for JS-heavy pages) the Actionbook Chrome extension — see below.
Neither is required if you only use `add-local`.

### Browser ingest backends

`ascent-research` picks between two actionbook backends based on
`ACTIONBOOK_BACKEND` (default `v2-mcp`):

| Env value | Path | What's needed |
|---|---|---|
| `v2-mcp` (default) | Cloud MCP at `edge.actionbook.dev/mcp` + Actionbook Chrome extension over WSS | `ACTIONBOOK_API_KEY` (an `ak_*` token), Chrome extension installed & signed in |
| `v1-cli` | Local `actionbook` CLI subprocess (offline-capable fallback, permanently supported) | The [`actionbook`]https://github.com/actionbook/actionbook binary on `PATH`, and your Chrome profile reachable by it |

**V2 setup**:

1. Install the **Actionbook Cloud (v2)** Chrome extension (v0.2.0-alpha.4
   or later). Unpacked-load it from `chrome://extensions` → Load unpacked.
2. Sign in via the extension popup.
3. Get an `ak_*` token from [actionbook.dev/dashboard/api-keys]https://actionbook.dev/dashboard/api-keys and export it:
   ```bash
   export ACTIONBOOK_API_KEY=ak_xxxxxxxxxxxxxxxx
   ```
   ⚠️ **Do not commit this token to git.** Prefer `.envrc` + direnv or a
   secret manager. `ascent-research` never echoes the token in error
   messages or logs.

**Recommended: dedicated Chrome profile.** V2 drives the page through
`chrome.debugger`, which Chromium will refuse to attach when other
extensions inject `chrome-extension://` content frames into the target
page (most password managers, AI sidebars, translation extensions, and
DevTools extensions do this). Symptom: every browser fetch fails with
`DEBUGGER_ATTACH_CONFLICT`.

The cleanest fix is a dedicated Chrome profile that only has the
Actionbook extension installed:

```bash
# macOS — launch a specific profile directly:
open -na "Google Chrome" --args --profile-directory="Profile 2"
```

(Replace `Profile 2` with the directory name shown at `chrome://version`
in your dedicated profile.)

**Other V2 env vars**:

| Env | Default | Purpose |
|---|---|---|
| `ACTIONBOOK_BACKEND` | `v2-mcp` | `v1-cli` to revert to subprocess; unknown values are fatal |
| `ACTIONBOOK_MCP_ENDPOINT` | `https://edge.actionbook.dev/mcp` | Point at staging or a local worker |
| `ACTIONBOOK_API_KEY` || `ak_*` token (required for v2-mcp) |
| `ACTIONBOOK_BIN` | `actionbook` | V1 path only; ignored under v2-mcp |
| `ACTIONBOOK_BROWSER_SESSION` || V1: shared session name. V2: tab-handle prefix (lets multiple ascent instances share one Chrome without colliding) |
| `ACTIONBOOK_STDOUT_CAP` | 16 MB | Cap on per-call response body (both backends) |

---

## Three shapes of research

### A. Survey a topic from public sources

```bash
ascent-research new "state-space models 2026" --slug ssm --preset tech
ascent-research batch \
  https://arxiv.org/abs/2111.00396 \
  https://arxiv.org/abs/2312.00752 \
  https://github.com/HazyResearch/state-spaces \
  --concurrency 4
ascent-research loop ssm --provider claude --iterations 10
ascent-research finish ssm --bilingual --open
```

PDF export is opt-in. The default backend is local and free: it uses an
isolated headless Chromium when available, so the HTML stays on your machine
and no paid API is required:

```bash
ascent-research synthesize ssm --bilingual --pdf
```

The local backend discovers Playwright Chromium first. If it is not installed,
run `npx playwright install chromium` or set `ASR_PDF_CHROME_BIN` to a known
safe browser binary. Desktop Google Chrome is not auto-launched by default; set
`ASR_PDF_ALLOW_SYSTEM_CHROME=1` only if you explicitly want that fallback.

### B. Deep-dive a library's source tree

```bash
ascent-research new "axum internals" --slug axum --preset tech
ascent-research schema edit        # set your "what to emphasize"
ascent-research add-local ~/axum/axum/src --glob '**/*.rs'
ascent-research loop axum --provider claude --iterations 12
ascent-research finish axum --open
```

### C. Structure your Obsidian vault

```bash
ascent-research new "my agent-SE notes" --slug notes --preset tech
ascent-research add-local ~/vault/agent-notes --glob '**/*.md'
ascent-research loop notes --provider claude --iterations 10
ascent-research wiki query "what's my stance on code review for AI?" \
  --save-as my-code-review-stance
```

### D. Audit GitHub star-trust signals

`github-audit` creates a deterministic evidence artifact first; the LLM only
interprets that artifact and any follow-up public context. It reports a
human-facing trust score, machine-facing risk score/band, confidence, reasons,
and evidence, not a hard “fake/real” verdict.

```bash
ascent-research github-audit dagster-io/dagster \
  --depth timeline --sample 500 --out audit.json --html audit.html
ascent-research new "dagster-io/dagster GitHub trust audit" \
  --slug dagster-trust --preset github-trust --tag fact-check
ascent-research add-local audit.json --slug dagster-trust
ascent-research loop dagster-trust --provider claude --iterations 8
ascent-research finish dagster-trust --open
```

Use `audit.html` when the user needs the trust decision surface directly:
trust score, risk score, confidence, metric dashboard, reasons, and evidence
gaps. Use the research session only for contextual follow-up around that
deterministic score.

Full command reference, error-code triage, loop contracts, and scenario
playbooks: see [`skills/ascent-research/SKILL.md`](skills/ascent-research/SKILL.md).

---

## Session layout

Each project is one directory under `~/.actionbook/ascent-research/<slug>/`.
Everything is plain files — markdown, JSON lines, SVG, TOML — so your
editor / grep / git / Obsidian all work without a custom client.

| File | Purpose |
|------|---------|
| `session.md` | Narrative — numbered sections, overview, aside. Report spine. |
| `session.jsonl` | Append-only event log. Sources, attempts, loop steps. Authoritative. |
| `SCHEMA.md` | User-editable session guidance. Loop re-reads each turn. |
| `wiki/*.md` | Persistent entity / concept / analysis pages with cross-links. |
| `diagrams/*.svg` | Hand-drawn figures inlined into the HTML report. |
| `raw/` | Raw fetched content, one file per accepted source. |
| `report.html` | Rendered editorial output — wiki TOC, inline SVGs, optional bilingual toggle. |
| `report.pdf` | Optional local PDF export of `report.html`, created only by `synthesize --pdf` or `--pdf-output`. Defaults to isolated local Chromium. |

Override the root via `ACTIONBOOK_RESEARCH_HOME=/some/path`. Legacy
`~/.actionbook/research/` is read as a fallback so sessions from
v0.2 keep working.

---

## Agent integration

`skills/ascent-research/SKILL.md` is a bundled Claude Code / Codex skill
describing the full workflow with nine scenario playbooks, error-code
triage, and build-target matrix. Expose it on your global skill path:

```bash
ln -s "$PWD/skills/ascent-research" ~/.claude/skills/ascent-research
```

---

## Development

```bash
cargo test -p ascent-research                         # core suite
cargo test -p ascent-research --features autoresearch # + loop suite (fake provider)
```

All integration tests use a `FakeProvider` replaying scripted JSON
turns, so the full suite never hits a real LLM and needs no network.

---

## Project lineage

- Core 2-file resume loop inherited from
  [karpathy/autoresearch]https://github.com/karpathy/autoresearch
- Per-session wiki layer inspired by karpathy's
  [LLM Wiki gist]https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f
- Widget / dashboard pattern borrowed from
  [pi-autoresearch]https://github.com/davebcn87/pi-autoresearch
- Previously named `research-rs` (v0.1 / v0.2); renamed to
  `ascent-research` in v0.3 to foreground the incremental-research story

---

## License

Apache-2.0.