Generate an Obsidian knowledge graph from your GitHub PRs, JIRA issues, and Confluence pages — automatically.
GitHub PRs + JIRA Issues + Confluence Pages → Auto-Categorized Notes → Obsidian Vault with [[wikilinks]]
Your entire engineering history as a searchable, interconnected knowledge graph. Updated daily. No manual work.
From GitHub:
- PR Notes — one note per pull request, with commits, topics, and cross-links
- Repo Maps — Maps of Content per repository, listing all your PRs
From JIRA:
- Issue Notes — one note per JIRA issue, with status, priority, description, and labels
From Confluence:
- Page Notes — one note per Confluence page you've contributed to
Cross-source:
- Topic Maps — Auto-clustered by engineering topic (e.g., Clock, CI/CD, Memory). Same keywords categorize PRs, JIRA issues, AND Confluence pages into shared topic MOCs
- Weekly Notes — Weekly activity grouped by repo
- Monthly Notes — Monthly rollups with per-repo and per-type breakdown
- Expertise Profile — Auto-generated "Areas of Expertise" with bar charts
- Dashboard — Stats, streaks, and recent activity at a glance
- Color-Coded Graph — Each source type and repo gets its own color
- Offline Mode — Vault regenerates from local cache, even without any API access
---
title: "BEV-179: [EDGE_TOP] bid mismatch"
type: issue
jira_key: "BEV-179"
project: "BEV"
status: "Done"
issue_type: "Bug"
priority: "Medium"
topics:
- "Verification"
---
# BEV-179: [EDGE_TOP] bid mismatch
- **Project:** Bertha-Edge-Verification (`BEV`)
- **Status:** Done
- **Type:** Bug
## Topics
- [[Verification]]
## Links
- [JIRA](https://your-company.atlassian.net/browse/BEV-179)Every [[wikilink]] connects to another note — repos, topics, weeks, issues — forming a navigable graph.
- Python 3.10+
- GitHub CLI (
gh) — authenticated withreposcope - Obsidian — to view the generated vault
- Atlassian account (optional) — for JIRA and Confluence integration
git clone https://github.com/seungbinshin/opsidian-graph.git
cd opsidian-graph
python3 -m venv .venv
source .venv/bin/activate
pip install -e .Copy the example env file and fill in your values:
cp .env.example .envEdit .env:
# Required for JIRA + Confluence (get token at https://id.atlassian.com/manage-profile/security/api-tokens)
ATLASSIAN_EMAIL=your-email@company.com
ATLASSIAN_TOKEN=your-api-token
ATLASSIAN_URL=https://your-company.atlassian.net
# Optional — for LLM-powered topic extraction and weekly summaries
ANTHROPIC_API_KEY=sk-ant-....env is gitignored — your secrets stay local.
The init command auto-discovers which GitHub repos you've contributed to:
opsidian-graph init --org <YOUR_ORG>This creates config/repos.yaml with every repo you've touched.
Important: Edit config/repos.yaml to keep only repos you actively modify.
Ask yourself: "Which repos do I open PRs in regularly?" Keep those, delete the rest.
Also add your JIRA projects and Confluence spaces:
org: My-Company
author: my-github-username
# JIRA projects to sync (issues assigned to you)
jira_projects:
- PROJ
- BACKEND
- INFRA
# Confluence spaces to sync (pages you contributed to)
confluence_spaces:
- Engineering
- Architecture
repos:
- name: backend-api
description: "Main backend service"
color: "#4A90D9" # Blue in Obsidian graph
- name: infra-k8s
description: "Kubernetes infrastructure"
color: "#50C878" # GreenHow to find your JIRA project keys: Look at your JIRA issue URLs — the prefix before the number (e.g.,
PROJ-123→ project key isPROJ).How to find your Confluence space keys: Look at your Confluence page URLs — the space key appears after
/spaces/(e.g.,/spaces/Engineering/pages/...).
Topics are keyword patterns that auto-tag PRs, JIRA issues, AND Confluence pages. Edit config/topics.yaml:
topics:
# Each topic has regex patterns matched against titles and descriptions
# Use \b for word boundaries so "ci" matches "CI" but not "special"
Database:
- "\\bdb\\b"
- "\\bmigration\\b"
API:
- "\\bapi\\b"
- "\\bendpoint\\b"
CI/CD:
- "\\bci\\b"
- "\\bworkflow\\b"How to pick good topics: Look at your recent PR titles and JIRA issue summaries. What words keep appearing? Those are your topics.
Items that don't match any keyword get labeled "Uncategorized". If you set ANTHROPIC_API_KEY, unmatched PRs are classified by an LLM instead.
# Without LLM (free, uses keyword matching only)
opsidian-graph sync --full --no-llm
# With LLM (requires Anthropic API key)
opsidian-graph sync --full- Open Obsidian
- Click the vault switcher (bottom-left)
- Select "Open folder as vault"
- Choose the
vault/folder inside this project - Open the Graph View (left sidebar) to see your knowledge graph
- (Optional) Install the 3D Graph community plugin for an interactive 3D visualization: Settings > Community plugins > Browse > search "3D Graph" > Install > Enable
# Incremental sync — only fetches new/updated items (fast)
opsidian-graph sync
# Full re-sync — re-fetches everything
opsidian-graph sync --full
# Regenerate vault from cache — no internet needed
opsidian-graph generateSet up a weekly cron job so your vault stays fresh without re-reading already-synced items:
# Create log directory
mkdir -p /path/to/opsidian-graph/logs
# Open crontab editor
crontab -e
# Add this line — syncs every Monday at 9:00 AM (adjust path to your install)
0 9 * * 1 /path/to/opsidian-graph/.venv/bin/opsidian-graph sync --no-llm >> /path/to/opsidian-graph/logs/sync.log 2>&1How incremental sync works: The tool tracks a last_updated_at timestamp per repo/project in .opsidian_state.json. Each sync only fetches items modified after that timestamp — it never re-reads already-synced content. This makes weekly syncs fast even with large histories.
| Cron field | Meaning |
|---|---|
0 9 * * 1 |
Every Monday at 9:00 AM |
0 9 * * * |
Every day at 9:00 AM |
0 */6 * * * |
Every 6 hours |
Verify it's working:
# Check your crontab
crontab -l
# Check sync logs
tail -20 /path/to/opsidian-graph/logs/sync.log
# Check last sync time
cat .opsidian_state.jsonNote: cron jobs require your Mac to be awake. If your machine is asleep at 9 AM Monday, the sync will be skipped until the next trigger. For a more reliable alternative on macOS, use
launchd(see below).
Alternative: launchd (macOS-native, runs even after wake)
Create ~/Library/LaunchAgents/com.opsidian-graph.sync.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.opsidian-graph.sync</string>
<key>ProgramArguments</key>
<array>
<string>/path/to/opsidian-graph/.venv/bin/opsidian-graph</string>
<string>sync</string>
<string>--no-llm</string>
</array>
<key>WorkingDirectory</key>
<string>/path/to/opsidian-graph</string>
<key>StartCalendarInterval</key>
<dict>
<key>Weekday</key>
<integer>1</integer>
<key>Hour</key>
<integer>9</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/path/to/opsidian-graph/logs/sync.log</string>
<key>StandardErrorPath</key>
<string>/path/to/opsidian-graph/logs/sync-error.log</string>
</dict>
</plist>Load it:
launchctl load ~/Library/LaunchAgents/com.opsidian-graph.sync.plistUnlike cron, launchd will run the missed job when your Mac wakes up.
All data is cached locally in cache/ (PRs, JIRA issues, Confluence pages). The generate command rebuilds the vault entirely from cache — no API access needed.
This means:
- Your vault survives losing access to private repos and company Atlassian (e.g., leaving a company)
- You can regenerate with different templates without re-fetching
- The cache is your portable engineering archive
vault/
├── Dashboard.md ← Home page with stats, streaks, links
├── Expertise.md ← Auto-generated Areas of Expertise profile
├── PRs/ ← One note per GitHub PR, organized by repo
│ ├── backend-api/
│ └── infra-k8s/
├── Issues/ ← One note per JIRA issue, organized by project
│ ├── PROJ/
│ └── BACKEND/
├── Pages/ ← One note per Confluence page, organized by space
│ ├── Engineering/
│ └── Architecture/
├── Repos/ ← Map of Content per repository
├── Topics/ ← Map of Content per topic (cross-source!)
├── Weekly/ ← Weekly activity notes
├── Monthly/ ← Monthly rollup notes
└── .obsidian/
└── graph.json ← Color config for graph view
org: Your-Org # GitHub organization name
author: your-username # Your GitHub username
vault_path: vault # Output directory (default: vault, relative to project root)
# Use absolute path for custom location, e.g.:
# vault_path: "/mnt/c/Users/me/Documents/OpsidianVault"
jira_projects: # JIRA project keys (optional)
- PROJ
- BACKEND
confluence_spaces: # Confluence space keys (optional)
- Engineering
repos:
- name: repo-name # Exact GitHub repo name
description: "..." # Shows in Repo Map of Content
color: "#4A90D9" # Hex color for Obsidian graph viewtopics:
Topic Display Name:
- "\\bkeyword\\b" # Regex pattern (case-insensitive)
- "\\bother-keyword\\b" # Multiple patterns per topic OKPatterns are matched against titles AND descriptions of PRs, JIRA issues, and Confluence pages. Use \\b for word boundaries.
ATLASSIAN_EMAIL=... # Your Atlassian login email
ATLASSIAN_TOKEN=... # API token from id.atlassian.com
ATLASSIAN_URL=... # e.g., https://your-company.atlassian.net
ANTHROPIC_API_KEY=... # Optional, for LLM featuresTo access your vault from multiple devices (e.g., work laptop + personal machine), push it to a private GitHub repo and use the Obsidian Git plugin for auto-sync.
If you want the vault generated outside the project directory (e.g., a shared folder on Windows from WSL), set vault_path in config/repos.yaml:
vault_path: "/mnt/c/Users/<username>/Documents/OpsidianVault"cd /path/to/vault
git init
git add -A
git commit -m "Initial vault sync"
gh repo create <username>/opsidian-vault --private --source=. --pushgit clone https://github.com/<username>/opsidian-vault.gitOpen the cloned folder as an Obsidian vault.
Install the Obsidian Git community plugin to auto pull/push on a schedule (e.g., every 5 minutes), keeping the vault in sync without manual git commands.
Important: Always use a private repo — your vault may contain internal project data (JIRA issues, PR details, Confluence pages).
opsidian_graph is part of the opsidian knowledge graph ecosystem:
opsidian_core ← shared library (cache, categorize, template, write)
│
├── opsidian_graph ← THIS PROJECT: work knowledge graph
├── drive_og ← personal knowledge graph (Google Drive)
└── opsidian_meta ← unified analysis vault (reads both caches)
| Project | What it does |
|---|---|
| opsidian_core | Shared library for all graph generators |
| opsidian_graph | Work knowledge graph (GitHub PRs, JIRA, Confluence) |
| drive_og | Personal knowledge graph (Google Drive) |
| opsidian_meta | Unified productivity analysis (timeline, focus reports, gap detection) |
After syncing with opsidian_graph, you can run opsidian_meta to generate cross-domain productivity reports that combine your work and personal activity.
See CONTRIBUTING.md for how to fork, develop, and submit pull requests.
.env— gitignored, contains your API credentialsvault/andcache/— gitignored, contain data from private repos and company Atlassian- The tool code itself is safe to share publicly
- Python 3.10+, Jinja2, PyYAML
- GitHub CLI (
gh) for GitHub API access atlassian-python-api+requestsfor JIRA and Confluencepython-dotenvfor credential management- Anthropic API (optional, for LLM-powered features)