Skip to content

Import Wordcell and Jungle captures

Markdown · Agent index

Sponge has importers for Wordcell capture bundles and Jungle Reading notes only. There is no importer for Pocket, Instapaper, Readwise or browser bookmarks; add those links with sponge add URL or sponge saves add URL.

Import saved captures, notes, and reading state through a source manifest. The import leaves the source files unchanged.

Import is additive. It never changes Jungle files, reading authority, published selection or source bundles. Explicit export is private by default; import does not publish anything. Use an owner-prepared source manifest beside the capture directories:

{
"schemaVersion": 1,
"namespace": "jungle",
"entries": [
{
"id": "existing-external-id",
"bundle": "captures/example",
"privacy": "private",
"notes": [{"id": "existing-note-id", "body": "My reading note"}],
"readingState": {"read": true}
}
]
}

bundle must be a confined relative directory path with no symbolic-link traversal. privacy is required for every entry; use published only for an already published source association. IDs and note IDs must remain stable. The source manifest is bounded to 1 MiB/1,000 entries; each entry admits up to 100 notes of 64 KiB each. Do not include passwords, cookies or runtime paths.

Terminal window
sponge import /absolute/source/manifest.json --dry-run --limit 20 --json
sponge import /absolute/source/manifest.json --apply --limit 20 --json
sponge import /absolute/source/manifest.json --apply --offset 20 --limit 20 --json

The default is a dry run. Follow nextOffset for bounded batches. Each entry reports ready/imported/duplicate/unsupported/failed independently. A custody or owner conflict stops the batch and returns the blocked entry as nextOffset. After interrupted worker recovery, rerun the same batch; atomic import receipts prevent duplicate revisions and notes. An explicitly cancelled job stays cancelled; it is not automatically revived by import.

Released Wordcell web or PDF verifiers validate each bundle before copying. Import computes current content digests and records them separately from the historical verification result. Missing legacy document/asset digests remain historicalIntegrity: unavailable, and the readable item remains partial. Mismatched hashes and unsupported/blocked captures are rejected individually.

Source privacy and external IDs remain in revision metadata. Imported notes and reading state are committed atomically with the revision and import receipt. Existing user reading choices win; conflicting text for an existing imported note ID fails that entry without changing the previous revision. No source reading projection or consumer switch is part of this command.

Terminal window
sponge import jungle /absolute/jungle --dry-run --json
sponge import jungle /absolute/jungle --apply --json

This reads Jungle in place and never writes to it. Each kb/notes/reading/<slug>.md note names its capture in relations.synthesizes (or evidenced-by for the note form) as articles/<slug>/<slug>; the bundle is that directory under kb/. Per note, in one batch of up to 1,000:

  • The capture is imported through the verified bundle path above (namespace jungle, external id = the capture link, privacy always private), so the item and revision do not depend on the note’s publication state.
  • The whole note becomes an editorial derivation (gist, every idea and quote, source, form, frontmatter, raw Markdown and its sha256), accepted through the logged review.note path. Digest, social, note and conversation forms are all kept; only a digest note is parsed strictly.
  • A digest note is also converted to Digest v2: the Gist’s first sentence is the lead and the rest its context; each idea’s bold claim and detail are kept as written. Each quote is kept only when it occurs in the revision’s Markdown as written (typography and whitespace folded; a match that only works across Markdown markup does not count) and has at least four words, with its attribution. As in the pipeline, quotes over the six-quote cap or the quoted word budget (at most 150 words and 10% of the source, with a 25-word floor) are dropped whole, longest first and then later in the note first, never the last one (budget); a single quote still over budget fails the note. Each kept quote goes to the idea sharing the most content words with its claim and detail (ties to the earliest idea), at most two per idea; an extra goes to the next best idea with room, else is dropped. Dropped quotes are reported per note (quotes.dropped, by position and reason). A note that then passes every v2 rule is stored as a Digest v2, accepted per field, linked to the editorial object by its input hash. Anything else is reported not-convertible with its reasons (for example ideas:quote-count when no quote survives, or gist.lead:too-long); quote text is never altered and owner text is never truncated or rewritten.
  • reading.status sets visibility through the logged setter. Jungle’s kb/notes/reading/AGENTS.md treats published as explicit public approval and keeps drafts out of the site, and its generated site lists exactly the published notes, so published sets public and draft restores private. Any other status leaves the default policy (private for imports). Capability URLs, local files and account captures are never made public (guarded).
  • A local capture (a scanned PDF or file with no web URI of its own) takes its web address from the note: an http(s) reading.source_url becomes the item’s primary shareable URI (origin metadata, derived like a captured locator, so fragments, click trackers and credential-like fields are dropped) and the file’s urn:sha256: stays as an alias. The item is then classed as an import rather than a local file, so published makes it public. A capability source_url is never recorded (uri: capability) and the item stays guarded. The note’s title replaces the capture’s title (often a file name or OCR text) through the logged title field, unless the title was changed in Sponge since (kept-user-edit). A web capture keeps its captured title (title: web-capture); sponge title set overrides either. When several notes share one capture, the first by file name decides both (other-note). A later capture revision keeps the recorded URI as primary; its capture title is replaced again on the next import. Re-importing a library imported before this rule applies it once.

Re-importing an unchanged note changes nothing. An edited note is a new editorial derivation (and a new v2 digest when it converts); earlier ones stay. A library imported before Digest v2 gains a v2 digest for each convertible note on the next import, beside its unchanged editorial object; an imported v1 digest stays, and the new v2 digest becomes current unless the user reviewed the v1 differently. User edits win: a visibility set in Sponge after the importer’s own write (tracked by local receipts) is kept, an editorial object the user rejected or cleared stops later notes from being auto-accepted, and a digest the user made or reviewed differently stops new imported digests. Deleted items are skipped.

The dry run reports per-note actions and counts (new items, editorial, digest, a histogram of the reasons notes do not convert, quotes assigned and dropped by reason, uri and title actions, visibility, skipped with reasons; report schema 2) without writing. It does not run the Wordcell verifier, so it needs no capture runtime: it predicts against the bundle’s own Markdown, localized from capture.json’s asset list; --apply verifies every bundle before anything is stored.

The Jungle checkout was read only during implementation. Corpus counts and source associations are private operational evidence, not committed fixtures; the tests use synthetic notes and captures. No consumer switch is part of this command.

Documentation drafted with AI and checked against the product source.