SuperAPI AI Directory

pace-config

General & other

View repository

Updated 10-15 19:58

About this skill

Configure a pace dashboard

Generate a config.yaml for pace from a user's description of what they want to track.

Source of truth: The snippets in this skill are illustrative and may lag behind the running version. Always confirm current shapes with:

pace adapters list
pace adapters explain <type>
pace transforms list
pace transforms explain <type>
pace presets list

Process

  1. Check whether a bundled preset already covers the user's request -- see "Start from a preset" below.
  2. Ask the user what topics, communities, or content types they care about.
  3. Map those interests to adapters (see reference below).
  4. Choose sensible params and transforms for each adapter.
  5. If multiple adapters feed the same topic, create a pipeline to merge and dedupe them.
  6. Design a layout that gives more space to primary interests.
  7. If the user wants summaries, filtering by relevance, or interest-based ranking, add LLM config.
  8. Write the final config.yaml.
  9. Run pace config check config.yaml to validate before handing off to the user.

Start from a preset

Before building from scratch, check whether a bundled preset already matches the user's theme:

pace presets list
# example          -- General software engineering (HN, Lobsters, GitHub, blogs, DEV.to)
# tech-news        -- Tech news from multiple sources
# ml-ai            -- AI and machine learning research
# daily-brief      -- Morning briefing with headlines and top stories
# product-launches -- Product launches and startup news
# release-tracker  -- Software release tracking
# academic-papers  -- Academic paper aggregation
# video-podcast    -- Video and podcast content
# ops-dashboard    -- Ops dashboard with iframes, bookmarks, counters

To use a preset as the starting point:

# Bun:
pace --preset tech-news

# Docker:
docker run -d -p 7453:7453 -v pace-data:/app/data ghcr.io/av/pace:latest --preset tech-news

Guidance: prefer preset + targeted edits when the user's ask matches a theme. Only build from scratch when no preset is close. When using a preset, copy it to config.yaml, make the minimal changes the user requested, and validate with pace config check.

Modifying an existing config

When the user already has a config.yaml:

Example -- "drop YouTube, show only LLM news from HN":

# BEFORE
adapters:
  - type: hackernews
    params:
      feed: top
      limit: 50
  - type: youtube
    params:
      channels: [UCXuqSBlHAE6Xw-yeJA0Tunw]
      limit: 15

# AFTER -- youtube adapter removed; hackernews gains an llm-filter transform
adapters:
  - type: hackernews
    params:
      feed: top
      limit: 50
    transforms:
      - type: llm-filter
        criteria: "relevant to LLM or AI research"
  1. Read the current file before making any edits.
  2. Make the minimal changes required -- remove/replace adapters the user no longer wants, add new ones, adjust params and transforms.
  3. Validate the edited config:
    pace config check config.yaml
    
    This catches schema errors and unknown adapter types without starting the server -- fast iteration loop.
  4. Restart required: pace reads config.yaml once at startup; it does not watch the file for changes. After writing the new config, the server must be restarted to pick it up:
    # Bun dev:
    # Ctrl-C, then: bun run dev
    
    # Docker Compose:
    docker compose restart
    
    # Docker direct:
    docker stop <container> && docker run ...
    
  5. Immediate panel refresh (after restart): trigger a panel to fetch content right away without waiting for refresh_interval:
    curl -X POST http://localhost:7453/refresh/<panel-id>
    # e.g.: curl -X POST http://localhost:7453/refresh/hackernews
    

Adapter reference

Every adapter has an optional refresh_interval (minutes, default 15, minimum 1) and an optional transforms list applied at ingest time. The name field disambiguates multiple instances of the same type.

hackernews

Hacker News stories.

# Authoritative shape: pace adapters explain hackernews
- type: hackernews
  params:
    type: top          # highest-priority alias (type > feed > stories); top, new, best, ask, show, job
    feed: top          # mid-priority alias; same values. Aliases: newest→new, front→top, askhn→ask, showhn→show, jobs→job
    stories: top       # lowest-priority alias for feed
    limit: 30          # max 200
    min_score: 0       # drop items below this point threshold

rss

Any RSS or Atom feed.

# Authoritative shape: pace adapters explain rss
- type: rss
  params:
    urls:
      - https://example.com/feed.xml
    limit: 50          # max 200; omit for unlimited (per feed)

reddit

Reddit subreddits.

Caveat: Reddit's public unauthenticated .json API often returns HTTP 403 upstream, so this adapter may not work without credentials. Bundled presets omit Reddit for this reason. For community discussions that work out of the box, prefer lemmy (used in tech-news and ml-ai presets).

# Authoritative shape: pace adapters explain reddit
- type: reddit
  params:
    subreddits: [programming, selfhosted]
    sort: hot          # hot, new, top
    limit: 25          # max 100
    min_score: 0
    time: day          # hour, day, week, month, year, all (for sort: top)

github

GitHub trending repos or releases from specific repos. Use mode to pick.

# Authoritative shape: pace adapters explain github
# Trending repos
- type: github
  params:
    mode: trending
    language: typescript   # optional language filter
    since: daily           # daily, weekly, monthly
    limit: 15              # max 50

# Releases from specific repos
- name: gh-releases
  type: github
  params:
    mode: releases
    repos: [facebook/react, oven-sh/bun]
    limit: 10              # max 50
    token: ${GITHUB_TOKEN} # optional, for private repos or rate limits

github-releases

Dedicated release tracker (alternative to github mode: releases).

# Authoritative shape: pace adapters explain github-releases
- type: github-releases
  params:
    repos: [denoland/deno, oven-sh/bun]
    limit: 5                 # optional, default 5, max 30 (per_page per repo)
    token: ${GITHUB_TOKEN}  # optional

lobsters

Lobste.rs stories.

# Authoritative shape: pace adapters explain lobsters
- type: lobsters
  params:
    feed: hottest      # hottest, newest
    limit: 25          # max 100
    min_score: 0
    tags: []           # optional tag filter

mastodon

Mastodon posts by hashtag or account.

# Authoritative shape: pace adapters explain mastodon
- type: mastodon
  params:
    instance: fosstodon.org    # default: mastodon.social
    hashtags: [rust, opensource]
    accounts: []               # optional account handles (@user@instance or user@instance)
    limit: 20                  # max 40
    min_favourites: 0          # minimum favourites count threshold
    only_media: false

youtube

YouTube channel or playlist feeds.

# Authoritative shape: pace adapters explain youtube
- type: youtube
  params:
    channels:
      - UCXuqSBlHAE6Xw-yeJA0Tunw   # channel IDs
    playlists: []                    # playlist IDs
    limit: 15                        # max 50

arxiv

Academic papers from arXiv.

# Authoritative shape: pace adapters explain arxiv
- type: arxiv
  params:
    categories: [cs.AI, cs.LG]   # arXiv category codes
    query: ""                      # optional search query
    limit: 20                      # max 100

stackexchange

Questions from Stack Exchange sites.

# Authoritative shape: pace adapters explain stackexchange
- type: stackexchange
  params:
    site: stackoverflow        # any SE site slug
    tags: [typescript, react]
    sort: hot                   # hot, activity, votes, creation
    limit: 20                   # max 100
    min_score: 0

devto

DEV.to articles.

# Authoritative shape: pace adapters explain devto
- type: devto
  params:
    tags: [typescript, webdev]
    username: ""         # optional, filter by author
    limit: 15            # max 30
    per_page: 20         # items per page; takes precedence over limit when both are set (max 30)
    min_reactions: 0
    top: 7               # period in days (1, 7, 30, 365; aliases: day→1, week→7, month→30, year/infinity/all→365)

producthunt

Product Hunt launches.

# Authoritative shape: pace adapters explain producthunt
- type: producthunt
  params:
    limit: 20            # max 50
    min_upvotes: 0
    enrich: false        # fetch full descriptions (slower)

podcast

Podcast episodes from RSS feeds.

# Authoritative shape: pace adapters explain podcast
- type: podcast
  params:
    feeds:
      - https://feeds.simplecast.com/54nAGcIl
    limit: 10            # max 50

twitter

Twitter/X lists and searches (requires authentication).

Caveat: Without params.bearer_token, this adapter always returns an empty list — no error, just no items. A Twitter API v2 bearer token is required for real usage. Run pace adapters explain twitter for the current param shape.

# Authoritative shape: pace adapters explain twitter
- type: twitter
  params:
    lists: []            # list IDs
    searches: []         # search queries
    bearer_token: ${TWITTER_BEARER_TOKEN}  # required; returns [] without it

npm

npm registry package search.

# Authoritative shape: pace adapters explain npm
- type: npm
  params:
    keywords: [typescript, cli]   # at least one of keywords or scope is required
    scope: "my-org"               # optional npm scope (without @)
    limit: 20                     # max 50
    sort: optimal                 # optimal, quality, popularity, maintenance
                                  # (aliases: popular→popularity, maint→maintenance, default→optimal)

lemmy

Lemmy federated community posts.

# Authoritative shape: pace adapters explain lemmy
- type: lemmy
  params:
    instance: lemmy.ml               # Lemmy instance domain
    communities: [technology, linux] # list of community names
    sort: hot                        # hot, new, top, active, mostcomments
                                     # (aliases: most_comments/comments→MostComments)
    limit: 25                        # max 50
    min_score: 0

wikipedia

Wikipedia featured content.

# Authoritative shape: pace adapters explain wikipedia
- type: wikipedia
  params:
    modes:                 # preferred array form
      - most_read          # most_read, featured, on_this_day, news
      - on_this_day        # aliases: mostread/popular→most_read, tfa→featured,
                           #          onthisday/otd→on_this_day, current_events/currentevents→news
    language: en           # ISO 639-1 language code
    limit: 20              # max 50

bookmarks

Curated bookmark links defined directly in config (no network fetch).

# Authoritative shape: pace adapters explain bookmarks
- type: bookmarks
  params:
    items:
      - title: "Linear"
        url: "https://linear.app"
        description: "Issue tracker"
        tags: ["work", "daily"]
      - title: "Figma"
        url: "https://figma.com"
        tags: ["design"]

counter

Fetches a JSON endpoint and extracts a numeric value for stat-card display. Use with display: counter on panels.

# Authoritative shape: pace adapters explain counter
- type: counter
  params:
    url: https://api.github.com/repos/oven-sh/bun
    json_path: stargazers_count
    label: "Bun Stars"
    # Optional:
    # unit: "%"
    # compare_url: https://metrics.internal/api/v1/error_rate?period=previous
    # compare_path: data.current
    # headers:
    #   Authorization: "Bearer ${METRICS_TOKEN}"

Transform reference

Transforms run at ingest time on adapter or pipeline results. They apply sequentially in the order listed.

# Authoritative shape: pace transforms explain latest
transforms:
  - type: latest
    count: 50

# Authoritative shape: pace transforms explain filter
  # Keep items matching any keyword
  - type: filter
    keywords: [ai, rust]
    fields: [title, body]   # default: all fields (title, body, source)

# Authoritative shape: pace transforms explain exclude
  # Remove items matching any keyword
  - type: exclude
    keywords: [sponsored, hiring]
    fields: [title, body]   # default: all fields (title, body, source)

# Authoritative shape: pace transforms explain sort
  # Sort items
  - type: sort
    field: timestamp        # timestamp, title, source
    direction: desc         # asc, desc

# Authoritative shape: pace transforms explain dedupe
  - type: dedupe
    strategy: url           # url, domain-normalized, title-similarity
    threshold: 0.85         # for title-similarity (0-1)
    keep: highest-score     # highest-score, earliest, latest

# Authoritative shape: pace transforms explain time-decay
  # Rank by engagement + recency
  - type: time-decay
    half_life: "12h"
    engagement_weight: 0.7
    recency_weight: 0.3
    decay: exponential      # exponential, linear
    min_score: 0.1
    annotate: false

# Authoritative shape: pace transforms explain keyword-score
  # Score by keyword relevance
  - type: keyword-score
    keywords:
      - term: "rust"
        weight: 10
      - term: "AI|machine learning"
        weight: 15
        regex: true
    min_score: 0
    annotate: false

# Authoritative shape: pace transforms explain cluster
  - type: cluster
    strategy: auto          # domain, keywords, source, auto
    min_cluster_size: 2
    max_clusters: 10
    similarity_threshold: 0.6
    annotate: false

  # --- LLM transforms (require llm config) ---
  # All LLM transforms gracefully degrade (items pass through unchanged) when no LLM is configured.

# Authoritative shape: pace transforms explain llm-summarize
  - type: llm-summarize

# Authoritative shape: pace transforms explain llm-filter
  - type: llm-filter
    criteria: "relevant to AI research"

# Authoritative shape: pace transforms explain llm-rank
  - type: llm-rank
    interests:             # optional; falls back to llm.interests in top-level config
      - open source software

# Authoritative shape: pace transforms explain llm-merge
  # Group and merge related items via LLM
  - type: llm-merge
    prompt: "Group items about the same topic"

Pipelines

Pipelines merge items from multiple adapters and apply cross-source transforms. Define them when the user wants a combined view.

pipelines:
  - name: combined
    sources: [hackernews, reddit]   # adapter names
    refresh_interval: 15            # optional
    transforms:
      - type: dedupe
        strategy: url
      - type: latest
        count: 40

A panel references a pipeline by using the pipeline name as its source.

Layout

Layout is a recursive flexbox tree. Each node is one of:

  • Container (direction + children): row or column flex wrapper.
  • Panel (panel + source): content feed panel. Optional display: counter renders stat cards instead of a content list.
  • Image widget (image): static image from a URL.
  • Text widget (text): static text block (plain, markdown, or html).
  • Iframe widget (iframe): embedded external page in a sandboxed iframe.
layout:
  direction: row           # row or column
  gap: 16                  # optional, px
  children:
    - panel: hackernews
      source: hackernews   # adapter name or pipeline name
      flex: 2              # relative size
      limit: 30            # max items to display

    - direction: column
      flex: 1
      children:
        - panel: reddit
          source: reddit
        - panel: releases
          source: gh-releases

    - panel: rss
      flex: 1
      source: rss
      limit: 20

Widget nodes

Widgets are layout leaves that display static content (no adapter source needed).

# Image widget
- image: https://example.com/banner.png
  alt: "Dashboard banner"          # optional alt text
  object_fit: cover                # cover, contain, fill, none (default: contain)
  max_height: 200px                # optional CSS max-height
  link: https://example.com        # optional clickable link (https or http://localhost only)
  flex: 1                          # optional relative size

# Text widget
- text: "Welcome to the dashboard"
  format: markdown                 # plain (default), markdown, html
  title: "Greeting"                # optional header
  flex: 1

# Iframe widget
- iframe: https://grafana.example.com/d/abc
  title: "Grafana"                 # optional header
  height: 400px                    # CSS length; takes priority over aspect_ratio
  aspect_ratio: 16/9               # fallback when height is not set (default: 16/9)
  sandbox: "allow-scripts allow-same-origin"  # optional sandbox tokens
  allow: "fullscreen"              # optional Permissions-Policy directives
  flex: 1

Counter display mode

Panels using the counter adapter should set display: counter to render stat cards:

- panel: metrics
  source: my-counter
  display: counter                 # renders stat cards instead of content list

The special source all shows items from every adapter. If layout is omitted entirely, pace renders a single "all" panel as the default.

Below 768px the layout collapses to a single column automatically.

LLM config (optional)

LLM transforms (llm-summarize, llm-filter, llm-rank, llm-merge) pass items through unchanged when the llm block is absent or misconfigured -- they never error out.

# Two concrete provider examples:

# Anthropic (Claude)
llm:
  provider: anthropic
  model: claude-sonnet-4-6
  api_key: ${LLM_API_KEY}
  interests:               # used by llm-rank
    - artificial intelligence
    - typescript

# OpenAI
llm:
  provider: openai
  model: gpt-4o
  api_key: ${LLM_API_KEY}
  interests:
    - artificial intelligence
    - typescript

Wiring the API key:

# Bun dev:
LLM_API_KEY=sk-... bun run dev

# Docker:
docker run -d -p 7453:7453 \
  -e LLM_API_KEY=sk-... \
  -v ./config.yaml:/app/config.yaml:ro \
  -v pace-data:/app/data \
  ghcr.io/av/pace:latest

The provider value is passed to pi-ai; supported providers include anthropic, openai, google, groq, mistral, and others -- see pi-ai docs for the full list.

Worked example

User says: "I want to follow AI/ML research, Rust programming news, and new open-source releases. I don't care about hiring posts."

Resulting config.yaml:

adapters:
  - type: hackernews
    params:
      feed: top
      limit: 50
    refresh_interval: 10
    transforms:
      - type: filter
        keywords: [ai, llm, rust, ml, neural, transformer, open source]
        fields: [title]
      - type: exclude
        keywords: [hiring, "who is hiring"]
        fields: [title]
      - type: latest
        count: 40

  - type: arxiv
    params:
      categories: [cs.AI, cs.LG, cs.CL]
      limit: 20
    refresh_interval: 60
    transforms:
      - type: latest
        count: 20

  - type: rss
    params:
      urls:
        - https://blog.rust-lang.org/feed.xml
        - https://this-week-in-rust.org/atom.xml
    refresh_interval: 30

  - type: lobsters
    params:
      feed: hottest
      limit: 25
      tags: [rust]
    refresh_interval: 15

  - name: gh-releases
    type: github
    params:
      mode: releases
      repos: [rust-lang/rust, huggingface/transformers, pytorch/pytorch]
      limit: 10
    refresh_interval: 60

pipelines:
  - name: ai-combined
    sources: [hackernews, arxiv]
    transforms:
      - type: dedupe
        strategy: title-similarity
        threshold: 0.8
      - type: latest
        count: 40

  - name: rust-combined
    sources: [rss, lobsters]
    transforms:
      - type: dedupe
        strategy: url
      - type: latest
        count: 25

layout:
  direction: row
  children:
    - panel: ai
      source: ai-combined
      flex: 2
      limit: 40

    - direction: column
      flex: 1
      children:
        - panel: rust
          source: rust-combined
          limit: 25
        - panel: releases
          source: gh-releases
          limit: 10