Skip to content

Repository files navigation

radar

License: MIT Python 3.12

A measuring instrument for the agentic/AI market — not a news aggregator, not a GitHub scraper. It's a research platform for accumulating, validating, and evolving structured knowledge about shifts in the AI/MCP/LLM ecosystem: collecting signals from GitHub, HN, Reddit, and AwesomeLists, filtering noise, clustering patterns against external analyst opinions, publishing to Telegram, and rendering an interactive knowledge graph.

This is a personal research instrument built for the author's own analysis — not a growth or audience product.

Live example: @radar_public
Interactive graph: mikkiola.github.io/radar
Architecture: docs/ARCHITECTURE.md — why this pattern works as a measuring instrument


Repository structure

radar/
├── src/                        pipeline scripts (see Scripts below)
├── tests/                      pytest suite (pythonpath = src, see pyproject.toml)
├── docs/                       mkdocs source + canonical docs (ARCHITECTURE/
│                                 ROADMAP/BACKLOG/CONSTITUTION.md, adr/)
├── scripts/                    verify.py, generate_adr_index.py
├── .github/workflows/          CI/CD pipeline (see CI/CD below)
├── .tooltempest.lock           pinned ToolTempest commit
├── SPEC.md                     active /spec target (idle unless a session is in progress)
├── mkdocs.yml                  Pages build config
├── pyproject.toml              pytest config
├── requirements-dev.txt        pytest, for the test job
├── requirements-security.txt   consolidated runtime+dev deps, for pip-audit
├── requirements_pages.txt      mkdocs + mkdocs-material, for the pages job
└── LICENSE                     MIT

The vault branch (data, separate git history) has its own structure — see Vault structure below.


How it works

GitHub / HN / Reddit / AwesomeLists
        ↓
radar_step0.py      collect projects
        ↓
filter.py           keyword filter by topic
        ↓
analyze.py          Claude: SHIFT or NOISE
        ↓
01_Assessments/     only SHIFT, URL deduplication
        ↓
patterns.py         Claude clusters assessments into patterns
        |
        → fetch_analysts.py   external analysts (Builder Radar, ...)
        |   04_Analysts/      structured claims from external sources
        ↓
02_Patterns/        active patterns with confirmation / divergence notes
        ↓
telegram_post.py    post to channel twice a day
        ↓
GitHub Pages        interactive graph of connections

Vault lives in the vault branch of the same repository. Obsidian reads it as a local vault. The graph is built from [[wikilinks]] in MD files and published automatically on every push.


Five-layer architecture

Layer 0 → Sources       GitHub / HN / Reddit / AwesomeLists
Layer 1 → Signals       repositories, articles, posts
Layer 2 → Assessment    SHIFT / NOISE  (analyze.py via Haiku)
Layer 3 → Patterns      signal clusters (patterns.py via Sonnet)
Layer 4 → Meta          our patterns + ExternalAnalyst[] + Forecasts (planned, not implemented)

Layer 4 adds external analysts as a separate input to pattern clustering. patterns.py receives both our assessments and structured claims from external sources, then looks for:

  • where opinions align — signal confirmed
  • our unique signal — we see it, analysts do not
  • external-only signal — analysts see it, we do not

Emergent properties

Personal research assistant — swap filter keywords and prompts, get a radar for any domain: biotech, policy, legal, VC deals.

Competitive intelligence — replace GitHub/HN with internal sources (Confluence, Jira, Slack via MCP). Track competitor moves and cluster them into behavioral patterns.

Self-updating knowledge base — the vault is a living Obsidian graph. Patterns connect via [[wikilinks]], the graph builds automatically. A human only reviews assessments in the "Human edit" block.

Falsifiable hypothesis trackerpatterns.py checks each pattern after 6 months: CONFIRMED / REFUTED / TOO_EARLY. Same falsification applies to external analyst claims. Built-in self-correction, not just data accumulation.

Multi-analyst intelligence layer — external analysts plug in via config. Builder Radar today, Simon Willison or Latent Space tomorrow. Each analyst carries a trust weight that affects pattern confirmation scoring when multiple analysts are active.

Public site from a private vault — vault branch → GitHub Pages → public interactive graph. Built with a 60-line custom script, no external graph dependencies.

AI-powered newsletter templatetelegram_post.py generates a post from vault assessments via Claude. Change the data source and prompt — get an automated digest for any topic, any channel.


Scripts

Script What it does Model Runs via
src/analyze.py SHIFT/NOISE evaluation, URL dedup Haiku radar job, daily
src/update_assessments.py Re-evaluate assessments older than 30 days Haiku radar job, daily
src/radar_step0.py Collect: HN + Reddit + GitHub (new + hot) + AwesomeLists helper module, imported by analyze.py
src/filter.py Topic filter (AI / MCP / LLM / automation) + traction check helper module, imported by analyze.py
src/scorecard.py OpenSSF Scorecard lookup, feeds the traction filter helper module, imported by filter.py
src/vault_write.py Frontmatter/vault-file write helpers helper module, imported by most scripts below
src/vault_language.py Detect assessment/pattern body language helper module, imported by patterns.py, update_assessments.py
src/check_frontmatter.py Validate frontmatter status/state values before push pre-push guard in radar, confirm_candidate, promote_candidates, recheck_lifecycle, analysts, check_models, patterns
src/confirm_candidate.py Human-in-the-loop confirm/reject of a CANDIDATE repo confirm_candidate job, on demand ($CONFIRM_REPO)
src/promote_candidates.py Promote quarantined candidates after 14 days promote_candidates job, daily
src/recheck_lifecycle.py Re-check VALIDATED_SHIFT lifecycle (frozen 6mo / releases stopped 12mo) recheck_lifecycle job, daily
src/fetch_analysts.py Parse external analysts, extract claims, save to 04_Analysts/ Haiku analysts job, every Friday
src/check_model_updates.py Check for new Claude model releases vs model_config.json check_models job, every Friday
src/patterns.py Clustering + archiving + falsification + external analyst input Sonnet patterns job, every Friday
src/telegram_post.py Generate post and publish to channel Sonnet publish job, twice daily
src/generate_graph.py Build graph.json from wikilinks pages job, on Pages build
src/generate_indexes.py Generate index.md for vault sections pages job, on Pages build
src/backfill_frontmatter.py One-off frontmatter migration manual only, not CI-invoked

CI/CD

Repository: github.com/mikkiola/radar, branches main (scripts) and vault (data). CI runs via GitHub Actions workflows in .github/workflows/: security, test, daily-run, monthly-lifecycle, weekly-patterns, publish, lint-vault, confirm-candidate, pages.

Workflow file Job(s) Schedule (UTC) Manual trigger
security.yml security_secrets, security_deps daily 22:00 yes
test.yml test — (push to main) no
daily-run.yml radar, promote_candidates, recheck_lifecycle daily 22:00 yes (with lifecycle_only/promote_only inputs)
monthly-lifecycle.yml recheck_lifecycle 1st of month, 17:00 yes
weekly-patterns.yml analysts, check_models, patterns Thursdays 22:00 yes
publish.yml publish daily 02:00 and 14:00 yes
lint-vault.yml lint_vault daily 22:00 yes
confirm-candidate.yml confirm_candidate yes (requires confirm_repo/confirm_decision inputs)
pages.yml build, deploy — (push to main or vault) yes

Schedules were converted from the old GitLab pipeline's Asia/Bangkok cadence to UTC; exact GitHub Actions run times may vary by a few minutes under platform load (documented GitHub behavior, not a defect).

patterns waits on analysts and check_models (needs: in weekly-patterns.yml), so both finish before it runs.


Environment variables

Stored as GitHub Actions repository secrets (Settings → Secrets and variables → Actions).

Variable What
ANTHROPIC_API_KEY Anthropic API key
GH_READ_TOKEN GitHub API token for signal collection (read-only)
GH_VAULT_PUSH_TOKEN GitHub token for pushing to the vault branch
TELEGRAM_BOT_TOKEN Telegram bot token
TELEGRAM_CHANNEL_ID Channel ID or username (@radar_public)
TELEGRAM_OWNER_ID Owner Telegram ID for notifications

Vault structure

vault branch/
├── 00_Inbox/           new projects for manual review
├── 01_Assessments/     SHIFT assessments (created by analyze.py)
├── 02_Patterns/        active patterns (created by patterns.py)
├── 03_Archive/         dormant and refuted patterns
├── 04_Analysts/        external analyst claims (created by fetch_analysts.py)
└── 99_System/          system files, published_posts.log

External analysts config

EXTERNAL_ANALYSTS = [
    {
        "name": "Builder Radar",
        "url": "https://buttondown.com/Builder-Radar/archive",
        "parser": "parse_buttondown",
        "weight": 0.8,
        "cadence": "weekly"
    },
    # {"name": "Simon Willison", ..., "weight": 1.0},
    # {"name": "Latent Space",   ..., "weight": 0.9},
]

Trust weights are inert with a single analyst. They activate when 3+ analysts are present and affect how strongly external confirmation influences pattern scoring.


Requirements / Setup

Python 3. Core scripts depend on requests, anthropic, and ghapi (installed directly in CI; there is no root requirements.txt). The docs/Pages build uses mkdocs and mkdocs-material, listed in requirements_pages.txt.

You'll need an Anthropic API key (ANTHROPIC_API_KEY) and, for Telegram publishing, a bot token and channel ID — see Environment variables above.


License

MIT — see LICENSE.


Author

Olga Stroganova, 2026.


Contributing

This is a personal research tool built for the author's own use. Pull requests are welcome but may not be reviewed quickly, or at all.

About

An AI ecosystem radar that detects structural shifts in open-source AI by analyzing GitHub, Hacker News, and Reddit, then clustering signals into long-term patterns.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages