linkding-ingest

Fetch recent Linkding bookmarks, analyze their content in child agents, and record insights to the vault

6 stars

Best use case

linkding-ingest is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Fetch recent Linkding bookmarks, analyze their content in child agents, and record insights to the vault

Teams using linkding-ingest should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/linkding-ingest/SKILL.md --create-dirs "https://raw.githubusercontent.com/lmorchard/decafclaw/main/contrib/skills/linkding-ingest/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/linkding-ingest/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How linkding-ingest Compares

Feature / Agentlinkding-ingestStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Fetch recent Linkding bookmarks, analyze their content in child agents, and record insights to the vault

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Linkding Bookmark Ingestion

Fetch recent bookmarks from Linkding, delegate per-bookmark analysis to child agents (so the heavy article text never enters this context), then apply their planned vault writes here.

**Children CANNOT write to the vault.** They research and return a structured plan; the parent applies the writes.

## Output Folder

All bookmark-derived pages live **directly under `agent/pages/bookmarks/`** as a flat namespace — no topical subdirectories. Children acting independently can't coordinate categorization and tend to create one-page subdirs that don't pay off. Use `[[wiki-links]]` between pages instead of folder structure to express relationships, and link out to related pages elsewhere in the vault.

## Configuration

| Env Var | Description |
|---------|-------------|
| `LINKDING_URL` | Linkding instance URL (e.g. `https://links.example.com`) |
| `LINKDING_TOKEN` | API token (Linkding Settings > Integrations) |

## Step 1: Fetch the bookmark list

Run the fetch script:

```
$SKILL_DIR/fetch.sh
```

With no args, the script auto-fetches everything since the last successful run (or the past 1 day on first run) and updates a workspace-side timestamp file when it succeeds. This is what scheduled cycles use.

**Backfill mode.** When invoked with arguments, the script forwards them directly to the underlying `linkding-to-markdown fetch` binary and skips the timestamp update — so a backfill doesn't clobber the scheduled-cycle state. Use this when the user asks for older bookmarks or a specific date range:

```
$SKILL_DIR/fetch.sh --days 30                       # last 30 days
$SKILL_DIR/fetch.sh --since 2026-04-01              # since a date
$SKILL_DIR/fetch.sh --since 2026-04-01 --until 2026-04-30
$SKILL_DIR/fetch.sh --query golang --days 365       # filtered fetch
```

Available flags (forwarded to the binary): `--days N`, `--since YYYY-MM-DD`, `--until YYYY-MM-DD`, `--query <text>`. See `$SKILL_DIR/bin/<platform>/linkding-to-markdown fetch --help` for the full list.

This outputs ALL matching bookmarks as markdown. Read the entire output to get the full list. Drop obviously low-signal bookmarks (duplicates, ephemeral content) before delegating — don't waste a child on them.

If the output is empty (no matching bookmarks), start your final summary with `HEARTBEAT_OK` and stop.

## Step 2: Delegate analysis with `delegate_tasks`

Call `delegate_tasks` with all of these:

- `allow_vault_read: true` — children must browse the vault for context.
- `return_schema`: the shape shown below.
- `tasks`: an array of per-bookmark task descriptions using the template below. One entry per bookmark.

The plural cap is 10 tasks per call. If you have more than 10 bookmarks, call `delegate_tasks` again with the next batch — don't try to cram everything into one call. Concurrent execution is capped server-side; you just submit batches.

### `return_schema`

```json
{
  "writes": [
    {
      "page": "agent/pages/bookmarks/example-slug",
      "content": "---\ntags: [ingested, example]\nsummary: one-line summary of the page\nsources:\n  - url: https://example.com\n    date: 2026-05-12\n    added_by: linkding-ingest\n---\n\nBody synthesizing the source with [[wiki-links]].\n\n## Sources\n- https://example.com (2026-05-12)"
    }
  ],
  "notes": "one-line note about what you wrote or why you skipped"
}
```

### Per-bookmark task description

Substitute the bookmark fields into this template. Send it verbatim to the child:

```
Analyze this bookmark and return a vault-write plan in the structured JSON shape requested by the return_schema. You CANNOT call vault_write — the parent will apply your plan.

URL: {bookmark_url}
Title: {bookmark_title}
Tags: {bookmark_tags}
Description: {bookmark_description}
Date: {bookmark_date}

Tools available to you:
- tabstack_extract_markdown(url) — fetch full article content
- vault_search(query) — search the vault for related pages
- vault_read(page) — read an existing vault page
- vault_backlinks(page) — find pages linking to a page

Steps:
1. Fetch the article with tabstack_extract_markdown. If it fails (paywall, dead link, error stub), work from the title/tags/description only.
2. Search the vault for related pages (vault_search). Read any strong matches (vault_read) so you can extend them rather than creating duplicates.
3. Decide what should be written:
   - Primary: ONE page for this bookmark. If a strong match already exists under `agent/pages/`, return its existing path and the FULL revised content. Otherwise create a new page directly under `agent/pages/bookmarks/` — flat namespace, no subdirectories.
   - Secondary (optional): a small number of related pages under `agent/pages/` to extend with a sentence or cross-link. Return the FULL updated content for each.
   - Cap total writes at ~3. If more pages seem relevant, mention them in `notes` instead of writing them.
   - Do NOT touch pages outside `agent/pages/`. If a strong match lives elsewhere (user notes, admin pages), leave it alone and link to it from your primary page.
4. Each page's content must include:
   - YAML frontmatter — see provenance rules below.
   - Body that synthesizes in your own words (short quotes only, attributed inline).
   - `[[wiki-links]]` to related pages you found.
   - A `## Sources` section. NEW pages: list this bookmark's URL + date. UPDATED pages: KEEP existing entries and append the new bookmark.

Frontmatter rules:
- NEW pages — include all three top-level fields:
  - `tags:` — list of topic tags
  - `summary:` — one-line summary
  - `sources:` — YAML list seeded with ONE entry for this bookmark (shape below)
- UPDATED pages WITH existing frontmatter — PRESERVE everything; just APPEND a new entry to the `sources:` list for this bookmark. Don't modify earlier entries; they record when each source was first added. You may refresh `summary` or extend `tags` if the new content materially changes them.
- UPDATED pages WITHOUT frontmatter — add a full frontmatter block. Seed `sources:` with just this bookmark. DO NOT backfill historical sources from the body `## Sources` section.

`sources:` entry shape:

```yaml
- url: https://example.com
  date: 2026-05-12
  added_by: linkding-ingest
```

`date` is YYYY-MM-DD. If the bookmark has no URL (rare), omit the `sources:` entry and just note the source in the body `## Sources` section.
5. If the bookmark isn't worth a page (low-signal duplicate, throwaway content), return `writes: []` with a one-line `notes` explaining why.
6. Keep your prose response short — one line is enough. The JSON block is what matters.
```

## Step 3: Apply the writes

`delegate_tasks` returns a `ToolResult` whose `data` field has the shape `{summary: {...}, results: [...]}`. Each entry in `results` represents one child and has `{index, ok, text, data}` — with `data.writes` and `data.notes` matching the per-child return schema you specified.

Iterate `data.results`. For each entry where `ok` is true, walk that entry's `data.writes` and call `vault_write(page=<page>, content=<content>)` for each item. The child has already synthesized and merged with existing content — don't second-guess.

For entries where `ok` is false, note the failure in your summary and move on. (The error message is in `entry.error`.)

If two writes target the same page (rare — two bookmarks on the same topic), the later one overwrites the earlier. Acceptable; mention it in the summary.

## Step 4: Summarize

Report what you processed and what changed:

```
Linkding ingest: processed N bookmarks.
Wrote: [[Page A]], [[Page B]], [[Page C]]
Skipped: M (low-signal)
Failed: K (see error)
```

If every bookmark was skipped or there were no bookmarks at all, start your summary with `HEARTBEAT_OK` on its own line followed by a brief note.

## Rules

- **Children cannot write to the vault.** They have read access (with `allow_vault_read: true`) but vault writes are categorically blocked for child agents. The parent applies all writes.
- **Don't fetch article content in this turn.** That's what children are for — your context stays clean.
- **All writes go under `agent/pages/`.** Children that propose paths elsewhere are buggy; skip those writes and note them.
- Convert relative dates to absolute dates.

Related Skills

ingest

6
from lmorchard/decafclaw

Fetch a URL, workspace file, or attachment and integrate its content into the vault — one primary page plus cross-linked updates to related pages

mastodon-ingest

6
from lmorchard/decafclaw

Fetch recent Mastodon posts and record interesting content to the vault

vault

6
from lmorchard/decafclaw

Unified knowledge base — shared Obsidian-compatible vault for curated pages, journal entries, and user notes

tabstack

6
from lmorchard/decafclaw

Your primary tool for any web, PDF, or research task. More powerful than web_fetch — prefer this for all research, web reading, and data extraction. Triggers on: 'tell me about,' 'what is,' 'look up,' 'find out,' 'research,' 'summarize this article,' 'read this PDF,' 'check this site,' 'what does this page say,' 'extract data from,' 'find the price on,' 'compare X vs Y,' 'is it true that,' or any URL/link. Handles JavaScript-heavy websites, PDFs, structured data extraction, content transformation, multi-source research with citations, and multi-step browser automation.

project

6
from lmorchard/decafclaw

Structured project workflow: brainstorm, spec, plan, execute multi-step tasks

postmortem

6
from lmorchard/decafclaw

Structured blameless analysis of what went wrong in this conversation — identifies root causes and proposes minimal, specific fixes

newsletter

6
from lmorchard/decafclaw

Compose and deliver a narrative newsletter summarizing autonomous agent activity in the window.

mcp

6
from lmorchard/decafclaw

Admin tools for inspecting and restarting connected MCP servers — status, resources, prompts. Does NOT expose tools provided by MCP servers; those appear as mcp__server__tool and are fetched via tool_search.

health

6
from lmorchard/decafclaw

Show agent diagnostic status — process, MCP, heartbeat, tools, embeddings

garden

6
from lmorchard/decafclaw

Vault gardening sweep — merge, link, split, and tidy agent pages

dream

6
from lmorchard/decafclaw

Review recent journal entries and conversations, distill insights into vault pages

claude_code

6
from lmorchard/decafclaw

Delegate coding tasks to Claude Code as a subagent. Use when asked to fix bugs, add features, refactor code, write tests, review code, or do any work that requires reading and editing files in a codebase. Triggers on: 'fix this bug', 'add a feature', 'refactor', 'write a test', 'review this code', 'update the config', 'clean up', or any request involving code changes in a repository.