一键导入
gnucash-import
Process WSFS bank statement PDFs into QIF files for GnuCash import
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Process WSFS bank statement PDFs into QIF files for GnuCash import
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Process Google Meet transcripts from Google Drive OR Apple Voice Memos into structured Obsidian vault notes with topic extraction, vault linking, Todoist action items, and calendar deadlines. Invoke with `/process-meeting`, `/process-meeting latest`, `/process-meeting YYYY-MM-DD`, or `/process-meeting voice [latest|today|YYYY-MM-DD]` for Apple Voice Memo recordings transcribed locally via mlx-whisper. Also trigger when user says "process meetings", "pull in transcripts", "process today's meeting", "process voice memo", "transcribe my memo", or asks to import meeting notes from Google Drive or voice memos.
Decompose YouTube videos into atomic Zettelkasten permanent notes in the Obsidian vault. Invoke with `/video-to-zettelkasten <youtube-url>` or when user says "ZK this video", "atomize this video", "extract notes from this video". Downloads transcript via yt-dlp, extracts concepts, and creates interlinked permanent notes plus a literature note.
Pull a YouTube video's transcript into context for discussion — no notes written. Invoke with `/video-transcript <youtube-url>` or when user says "pull the transcript", "transcript this video", "let me read this video first", "what does this video say". Downloads and cleans the transcript via yt-dlp, then summarizes it for conversation. Hand off to `/video-to-zettelkasten` when ready to make notes.
Companion skill for the mcp-atlassian MCP server. Provides correct parameter patterns, JQL quirks, and workflow recipes for Jira and Confluence tools. Load this skill before performing Atlassian operations to avoid common parameter errors.
Content exchange with the user via the Drafts app (macOS) using the `drafts` CLI. Default destination is Drafts; override to clipboard only when the user explicitly says "pbcopy", "clipboard", or "to clipboard". Drafts triggers: "copy it", "give it to me", "send it to me", "give me a draft", "send to drafts", "read it back", "what does it say", "pull from drafts", "get the draft", or /drafts. Primary method for delivering substantive content to the user.
Decompose books into atomic Zettelkasten permanent notes in the Obsidian vault. Invoke with `/book-to-zettelkasten` or when user says "ZK this book", "atomize this book", "extract permanent notes from this book", "decompose book into notes", "break this book into ZK notes", or wants to turn a book summary or full book text into linked atomic concept notes. Also use when user has an existing literature note they want to enrich with permanent notes, or when they paste book content and want it structured for their second brain.
| name | gnucash-import |
| effort | low |
| description | Process WSFS bank statement PDFs into QIF files for GnuCash import |
| user_invocable | true |
| trigger | /gnucash-import |
| arguments | <pdf_path> [pdf_path...] |
Process WSFS Bank statement PDFs into QIF files importable by GnuCash.
Copy config.example.json to config.json and fill in your paths:
cp config.example.json ~/.claude/skills/gnucash-import/config.json
Load settings from ~/.claude/skills/gnucash-import/config.json:
.gnucash fileAssets:Current Assets:Checking Account)payee_mappings.json for raw description → clean payee name mappingAdditional derived settings:
!Type:BankYYYYMM.qif<output_directory>/statement_metadata.jsonRun this to get existing mappings:
gunzip -c "<gnucash_file>" | python3 -c "
import sys, xml.etree.ElementTree as ET
tree = ET.parse(sys.stdin)
root = tree.getroot()
accounts = {}
for acct in root.iter('{http://www.gnucash.org/XML/gnc}account'):
name = acct.find('{http://www.gnucash.org/XML/act}name').text
acct_id = acct.find('{http://www.gnucash.org/XML/act}id').text
parent_el = acct.find('{http://www.gnucash.org/XML/act}parent')
accounts[acct_id] = {'name': name, 'parent': parent_el.text if parent_el is not None else None}
def get_path(aid):
parts = []
while aid and aid in accounts:
parts.append(accounts[aid]['name'])
aid = accounts[aid]['parent']
parts.reverse()
return ':'.join(parts[1:])
ns_trn = '{http://www.gnucash.org/XML/trn}'
ns_split = '{http://www.gnucash.org/XML/split}'
pm = {}
for txn in root.iter('{http://www.gnucash.org/XML/gnc}transaction'):
d = txn.find(f'{ns_trn}description')
if d is None or not d.text: continue
for s in txn.findall(f'.//{ns_split}account'):
if s.text in accounts:
p = get_path(s.text)
if p and not p.startswith('Assets:Current Assets:Checking'):
pm[d.text.strip()] = p
for k in sorted(pm): print(f'{k} -> {pm[k]}')
"
Also load payee_mappings.json from the skill directory for raw description → clean payee name mapping.
Also extract the full chart of accounts for categorizing unknown payees.
Use the Read tool to read the PDF. The WSFS statement format:
Mon DD) followed by type (ACH DEPOSIT, DEBIT CARD, POS PURCHASE, CHECK)-$9.18)For each transaction extract:
Mon DD + year from statement headerpayee_mappings.json. Match raw description substrings (case-insensitive) to clean payee names. Strip terminal numbers, addresses, masked account numbers (XXXX), TRAN DATE lines.-$ prefix, keep sign)Match cleaned payee names against the payee→account map from step 1 (fuzzy match is fine). For unknown payees, suggest a category from the chart of accounts based on the description. Mark uncertain matches with [?].
Before generating, check if the output QIF file already exists in the output directory. If it does, warn the user and ask before overwriting.
Compact format for known payees:
Jan 2026: 7 transactions, 7 known payees. Net: +$141.72 ✓
Only show detail table for unknown/uncertain payees:
Unknown/uncertain transactions requiring review:
| # | Date | Payee | Amount | Suggested Account |
|---|------------|----------------------|----------|--------------------------------|
| 3 | 01/15/2026 | Some New Vendor | -$50.00 | Expenses:Miscellaneous [?] |
Ask user to confirm or provide corrections (e.g., "3 -> Expenses:Office Supplies").
When user corrects an unknown payee, offer to add the mapping to payee_mappings.json for future use.
Write the QIF file to the output directory, named YYYYMM.qif.
QIF format:
!Account
NAssets:Current Assets:Checking Account
TBank
^
!Type:Bank
DMM/DD/YYYY
PPayee Name
T-amount
LAccount:Path
MTransaction Type
^
D = date in MM/DD/YYYYP = cleaned payee nameT = amount (negative for withdrawals, positive for deposits)L = GnuCash account pathM = memo (transaction type: DEBIT CARD, ACH DEPOSIT, POS PURCHASE, CHECK)^ = end of transaction recordAfter generating QIF, update statement_metadata.json in the output directory. This is a running JSON file keyed by YYYYMM with balance and transaction data extracted from the statement's Balance Summary section.
Read the existing file first, add/update the entry for this month, and write it back:
{
"YYYYMM": {
"statement_date": "MM/DD/YYYY",
"beginning_balance": 1234.56,
"ending_balance": 1345.67,
"deposits": 200.00,
"withdrawals": 88.89,
"transaction_count": 7
}
}
Verify continuity: the previous month's ending_balance should equal this month's beginning_balance. Warn if it doesn't.
Verify:
Report the QIF file path, then output reconciliation info:
Import in GnuCash: File → Import → Import QIF...
Reconciliation (Actions → Reconcile):
Statement Date: MM/DD/YYYY
Ending Balance: $X,XXX.XX