Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
단순 작업은 Bonobot이 담당합니다. 1Password와 Bitwarden를 이용해 로컬에서 청구서를 다운로드하는 오픈소스 도구입니다
Monkey work is Bonobot's job. Open-source, local-first invoice downloads with 1Password and Bitwarden — for humans and AI agents.
금융JavaScript · HTMLGitHub @intelia-technologies온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
Download SaaS invoices automatically — Chrome extension + agent CLI/MCP/Skill with 1Password & Bitwarden (macOS, Windows, Linux)
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗🌐 Website & installers: https://invoice-extractor.noscomelaia.com · Latest release
Automatically download invoices from SaaS billing pages. Providers are defined declaratively in JSON files — the engine interprets them generically.
Key advantage: Downloads use the provider sessions already open in Chrome. Optional profile synchronization has its own independent login; it never transfers provider sessions.
chrome://extensionsAfter editing files, click the refresh icon on the extension card in chrome://extensions.
The extension can fetch credentials (username, password, and 6-digit TOTP codes) directly from 1Password Service Account vaults (AI via OP_SERVICE_ACCOUNT_TOKEN_INTELIA and AI bots via OP_SERVICE_ACCOUNT_TOKEN_LANA in ~/.zshrc.local) without Touch ID prompts or storing secrets in browser storage.
com.intelia.invoice_extractor.op):
npm run install:1password
chrome://extensions.1Password Item override in the provider's settings, and fills username, password, and 2FA OTP automatically (1-step or 2-step flows). You can also click 🔑 Sign in with 1Password in the workflow panel at any time. Credentials are only typed on an HTTPS page whose host is (a subdomain of) a host saved on the vault item, the provider's billing host, or a sign-in domain the recipe declares in auth.loginDomains — hosts are never widened automatically to a parent domain. On any other page nothing is typed and the panel says which host was refused.Profile Sync or Invoice Extractor (or matching the sync service URL).bin/invoice-extractor.mjs (CLI), bin/invoice-extractor-mcp.mjs (MCP server for Claude Desktop
and other MCP clients) and skills/invoice-extractor/SKILL.md let an AI assistant download
invoices with the same provider recipes. Passwords are never given to the AI: they go from
1Password/Bitwarden straight into the provider's sign-in page.
One-time verification codes. Some providers (e.g. Holded) email or text a code after the password. The rule is: if the AI has access to the user's email, it reads the provider's code and uses it; if not, the user does it (typing it in the open browser window, or telling the AI). The code only reaches the AI if the AI reads it from the user's email or the user gives it.
invoice_extractor_run keeps that provider's page open for 10 minutes, finishes the other
providers and returns it under pendingVerification with a nextStep instruction; the AI then
calls invoice_extractor_submit_code({ verificationId, code }), which only types the code on a
page of that provider, signs in and returns the downloaded invoices. A wrong code can be retried.
Runs share one browser session and run one at a time; while a code is pending, a run for a
different client profile is refused until the code is submitted or released with
invoice_extractor_cancel_verification.run --wait-for-code[=minutes] prints a verification_code_required JSON line on stderr
and waits; the code is handed over with
echo <code> | invoice-extractor submit-code --id <verificationId> (through a short-lived
0600 file in the local state directory, deleted as soon as it is read) or typed in the
--headed window. Without the flag the provider fails with a clear message.The code is never logged, written to the manifest or state, or echoed back.
The extension works without an account. Open Profiles (or Sync: local only) to connect to a trusted synchronization service using your own username and password. Create an account on that service, then sign in with the same account on each computer. Save your current settings into a profile first: unsaved live settings are not uploaded.
Only saved profile names, active provider selections and provider configuration are synchronized. Workspace URLs and team/account IDs may be personal information: only connect to a service you trust. Cookies, provider logins, invoices, download history, workflow progress and the selected profile remain local. Receiving updated profiles does not change your live settings; explicitly Load a profile to apply them.
Saved changes synchronize in the background while Chrome is running, on interface opening, and approximately every minute (Chrome may delay background alarms). Offline changes remain on the device and retry later. After an expired or revoked session, disconnect and sign in again. Disconnect removes local login tokens, attempts to revoke that session, and keeps both the local and remote saved profiles.
If local and cloud copies both changed, synchronization stops and presents a choice: Keep this device or Use cloud profiles. This replaces the entire saved profile list, not just one profile. A newer cloud revision requires reviewing the choice again. The replaced copy is retained as one local replacement backup, available through Export replacement backup. Later imports or conflict choices overwrite that backup; routine cloud updates do not. Export it first if you need to keep it. Export profiles and Import profiles also work without an account. Import replaces saved profiles and, when connected, synchronizes that change. Documents are limited to 100 profiles and 256 KiB.
Cloud synchronization is optional. Without it, the extension, the agent CLI, the MCP
server and the Skill work fully in local mode: profiles live in
~/.config/invoice-extractor/state.json and can always be rebuilt from your
1Password or Bitwarden items (invoice-extractor profiles --sync-1p).
The extension only contains the sync client. It talks to any server that implements
the profile-sync HTTP contract (/config, /auth/register, /auth/login,
/auth/logout, /profiles) defined by profile-sync.mjs and sync-schema.mjs.
The managed backend operated by Intelia is maintained in a separate private repository.
npm test validates providers and runs the JavaScript synchronization/client tests.
| Provider | Download Method | Date Format |
|---|---|---|
| Amazon | click-download | D de MMMM de YYYY |
| CodeRabbit | click-download | auto |
| Elastic Cloud | direct-link | range |
| GitHub | fetch-blob | YYYY-MM-DD |
| GitHub Enterprise | fetch-blob | YYYY-MM-DD |
| Google Cloud | click-download | auto |
| Google Workspace | click-download | D/M/YY |
| Hetzner | direct-link | MMM DD, YYYY |
| Holded | fetch-blob | DD/MM/YYYY |
| Hover | debugger-print | MMM DD, YYYY |
| Lowi | click-download | Month YYYY |
| Naturgy | click-download | DD/MM/YYYY |
| OpenAI | chrome-download | auto |
| Shortcut | chrome-download | M/D/YYYY |
| Stripe | click-download | Month YYYY |
| Twilio | click-download | Month YYYY |
| Vonage/TokBox | fetch-blob | M/D/YYYY |
| Vultr | fetch-blob | YYYY-MM-DD |
| Webflow | direct-link | Month D, YYYY |
| ZeroSSL | direct-link | Month YYYY |
providers/ following the schema belowproviders/index.jsonnpm run validate — it must pass before the provider is acceptedEvery provider must declare "schemaVersion": 1. Add a $schema reference pointing at
providers/schema.json so your editor gives you autocomplete and inline validation while you
write the file. npm run validate (also wired to npm test) checks every provider against that
schema, and CI runs it on every pull request — see CONTRIBUTING.md for the
full workflow and selector-resilience guidelines.
{
"$schema": "./schema.json",
"schemaVersion": 1,
"id": "my-provider",
"name": "My Provider",
"icon": "🏢",
"billingUrl": "https://example.com/billing",
"readySelector": "CSS selector that indicates page is loaded",
"extract": {
"rows": "CSS selector for invoice rows",
"fields": {
"date": { "selector": "CSS relative to row" },
"downloadUrl": { "selector": "CSS", "attr": "href", "resolve": true }
},
"dateFormat": "auto",
"dedup": "downloadUrl"
},
"download": {
"method": "direct-link",
"filenameTemplate": "{{name}}_Invoice_{{date}}.pdf"
}
}
direct-link — Creates <a download> and clicks it (for direct PDF URLs)fetch-blob — fetch() with credentials + blob download (for same-origin PDFs)open-tabs — Opens URLs in new tabs for manual download (e.g., Stripe receipts)print-page — Opens the receipt page + triggers the print dialog (save as PDF)chrome-download — Opens the URL in a background tab and waits for a browser-initiated download; handles redirects, cookies, and JS triggers. Supports postLoadClick to press a button after load (e.g., Stripe's "Download invoice"). In agent mode the URL must be on the billing host, auth.loginDomains or download.allowedHostsdebugger-print — Uses chrome.debugger + Page.printToPDF to generate a PDF fully automatically, no print dialog (for receipt pages with no PDF link)click-download — Drives a sequence of in-row click steps (via the engine) to trigger the browser's own download, for providers with no extractable URL (e.g., open a popover, then click the download link)auto, M/D/YYYY, D/M/YY, DD/MM/YYYY, MMM DD, YYYY, Month D, YYYY, YYYY-MM-DD, Month YYYY, D de MMMM de YYYY, range
preSteps — Click tabs or wait for elements before extractionconfig — Per-user settings (workspace URLs, team IDs) stored in chrome.storage.localresolve: true — Resolve relative URLs to absoluteregex — Extract values from text using regex patternsdownloadLinks — Multiple download links per row (e.g., Elastic)urlTemplate — Construct download URLs from extracted fields (e.g., Vultr)fallbackRows — Alternative row selector if primary finds nothingpopup.js → loads providers/*.json → injects engine.js into tab → downloads
↓ ↓
popup.html provider JSON + config
(UI + workflow) (declarative definition)
Three layers:
engine.js) — generic runtime injected into billing pagespopup.js) — popup interface, floating window, state persistenceContributions are welcome — especially new providers and fixes for providers that have broken
because a billing page changed its markup. Please read CONTRIBUTING.md
before opening a pull request: it covers how to add a provider, the selector-resilience
guidelines that keep providers from rotting, the validation requirements (npm run validate),
and the security rules for the provider catalog.
Found a provider that stopped working? Open an issue using the 🔧 Broken provider template. Want a new provider supported? Use the ✨ New provider request template.
Released under the MIT License.