Import and sync broker CSV portfolio data to Google Sheets DataHub. Supports multiple brokers (Fidelity, Schwab, Vanguard, etc.)...
Refresh positions and balances from SnapTrade into family_office.db, then validate the snapshot against safety thresholds before anyone reasons off it.
family_office.db is the system of record. The Google Sheets DataHub was retired 2026-07-31; there is no spreadsheet to push to and no gdrive MCP configured.
Positions and balances come from the local DB, refreshed FIRST so it can never be stale. Follow the shared Sync-First + DB-Read pattern.
uv run python -m src.integrations.snaptrade.sync_db # writes positions + balances
uv run python -m src.integrations.snaptrade.sync_db --show # read back the snapshot
Completion criterion: the positions and balances tables carry this run's synced_at. Everything downstream reads the DB, not a CSV.
To refresh positions, transactions, and bank expenses together:
uv run python -m src.integrations.refresh_all
config/snaptrade-accounts.yaml declares each account's role and enabled flag. An account with no declared role refuses to sync rather than guessing. Cash-management accounts belong to SimpleFIN (TransactionSyncing), not here, so brokerage margin math stays clean.
⚠️ Capture the "before" state first, or these gates cannot fire.
sync_dbis a current-state store: it deletes each account's prior position rows and overwrites its singlebalancesrow (which is keyed onaccount_id). No history survives the refresh, so read the existing snapshot before running Step 0 and hold it in the session to diff against. There is noposition_historytable to fall back on.
# BEFORE Step 0 — capture the prior generation
sqlite3 family_office.db \
"SELECT symbol, quantity, average_purchase_price FROM positions ORDER BY symbol;"
sqlite3 family_office.db "SELECT * FROM balances;"
STOP conditions (require user confirmation):
FLAG conditions (alert but proceed): SPAXX off by $1-$100; pending activity off by more than $100.
When STOPPED: show a clear diff table, ask the user to confirm, proceed only after explicit approval.
SPAXX position value; it shows only settled money market.Dividend funds → Layer 2, growth → Layer 1, hedges → Layer 3. If a new ticker does not clearly match a pattern, mark it UNKNOWN - Manual Review Required and ask the user rather than guessing.
CSV import is a fallback and re-verification path only, not the primary flow. The IngestPositions workflow archives Portfolio_Positions_*.csv and Balances_*.csv from ~/Downloads into notebooks/updates/. Use it when a live source is down or the user explicitly wants an archive.
Classifier for Fidelity position exports: a header containing Ex-date is the dividend view; a header containing Average Cost Basis is the regular view. The dividend view and transaction history CSVs are still consumed by dividend-tracking and TransactionSyncing.
config/snaptrade-accounts.yamlSNAPTRADE_* keys are present in .envDATABASE_URL is set in .envfin-guru/data/user-profile.yamlconfig/snaptrade-accounts.yaml.claude/skills/_shared/SyncFirstDbRead.mdSkill Type: Domain (workflow guidance) Enforcement: BLOCK (data integrity critical) Priority: Critical