oto-cli 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oto_cli-1.0.0/.claude/settings.local.json +20 -0
- oto_cli-1.0.0/.gitignore +13 -0
- oto_cli-1.0.0/CLAUDE.md +117 -0
- oto_cli-1.0.0/LICENSE +21 -0
- oto_cli-1.0.0/PKG-INFO +171 -0
- oto_cli-1.0.0/README.md +131 -0
- oto_cli-1.0.0/TODO.md +45 -0
- oto_cli-1.0.0/docs/concepts.md +136 -0
- oto_cli-1.0.0/docs/create-connector.md +174 -0
- oto_cli-1.0.0/docs/gmail-oauth-setup.md +125 -0
- oto_cli-1.0.0/docs/google-service-account-setup.md +154 -0
- oto_cli-1.0.0/docs/installation.md +134 -0
- oto_cli-1.0.0/oto/__init__.py +3 -0
- oto_cli-1.0.0/oto/cli.py +74 -0
- oto_cli-1.0.0/oto/commands/__init__.py +0 -0
- oto_cli-1.0.0/oto/commands/anthropic.py +64 -0
- oto_cli-1.0.0/oto/commands/audio.py +91 -0
- oto_cli-1.0.0/oto/commands/browser.py +257 -0
- oto_cli-1.0.0/oto/commands/company.py +23 -0
- oto_cli-1.0.0/oto/commands/enrichment.py +152 -0
- oto_cli-1.0.0/oto/commands/folk.py +238 -0
- oto_cli-1.0.0/oto/commands/google.py +355 -0
- oto_cli-1.0.0/oto/commands/notion.py +58 -0
- oto_cli-1.0.0/oto/commands/pennylane.py +272 -0
- oto_cli-1.0.0/oto/commands/search.py +36 -0
- oto_cli-1.0.0/oto/commands/sirene.py +201 -0
- oto_cli-1.0.0/oto/commands/skills.py +91 -0
- oto_cli-1.0.0/oto/commands/whatsapp.py +47 -0
- oto_cli-1.0.0/oto/config.py +167 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/07a366cf2d7a0f77e7a1736805e94786e6053bb581b6b7179591b71d34843ce8.json +98 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/0b21878dbd4bf5a67ff52104361a07ee575b03a075b7b81cbc4a0d5d4045f759.json +142 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/0bf47e753ec29da03776bca010122393b4fc188af7f28dd11b456a74e5cae8f4.json +98 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/1b2c924688fdcef8b7e3748f92ed4fdb232cadb387a7e9e157c438d32374ff97.json +4356 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/2a66512043d3531dc900b8244fc13972c0abfe7760c10fbb7fc21f309238ad0b.json +132 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/2b59aed15d0c747ec2cae70a1eb3f554b3e170875110b82f8e4614b761c84dcf.json +142 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/2f7d1284021d30e842cc9a2b506e87b4a32c61e8e9abb616aec37828c441231d.json +220 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/33eb548bce70fb7b0e8eb09211ba6c03ad22b6e7a289606b05c5d690f724d8e4.json +1659 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/364d3a5e790f3d8b5137aae0a5a9ee151cd8c9f7dacb4fd669220f968405ea36.json +88 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/3e7e836a6bf18f951d4887fefeacb146473491ad2cbaa1793c79af08b7ef45b6.json +132 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/3f95b2d8bdf3d47e8f6c167d6d9a0889f27b64e8c78f0afdad538fecae070858.json +98 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/46c38d10065fb68ca912692df53b6e54eb1f6f9cdff342de563020917e27ccf5.json +98 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/51fa4d44044d751ca2319d87d607bd58a01004a24a8065808d65c273b35d3a10.json +210 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/59888e9c297cda6836afb560fb4048b100f98eb3abead8b175fe92fbf858210b.json +186 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/60df8d17a4e08fdbafb0ea398ff68d45cb79da7c01bd129e98264be1bff7ed1d.json +176 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/62a44af3f86b5841d905789565a0208f80c1a304bcfc8889ccd55f61f29508b2.json +132 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/69ec094fc12a40d1591abbd4f21295af672389963f900ea421a6d75b6f21f03b.json +176 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/703fc49f07e73447e176fa69f31c7ff7bbb7c8c95325af4ca1a8664385bfeb0b.json +98 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/7e247cf818c2a930de8a5a8599716900cb5af90570a9f701699dd8897fe43c8d.json +88 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/86741d020ca89789bda8156315ead5e980068c19754baf6e611ffc618557dc06.json +115 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/8cc6e5e1d955310412df09c9179ec67d42767d1b557262e28bc2afea05ab7c24.json +210 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/989d88c22dd009e5683987e70671d1e20fd6a5a3e9ee7670db9ea602fe8fbded.json +4605 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/999d01d80c8ef0c856572028e31e701cad8c5704b8886388b756d32ef50cbfaf.json +132 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/9f10e5fa6404211b156b2f5c22a0644e5eb0c49774d2b4f8d768211f0c6aea22.json +3380 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/9f950bdfc2aeb9ae5e1b185e827636f83fa44a9d7de0d1462d87926508b26907.json +142 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/a4719c76c9ff4c4b056e87689e2f487770c35d82d70acb098ead7712e0d3be8d.json +142 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/a808160a7352fa1a3029ef1e2929dfa99b5021b0d22ce1cfb9efe3c68f7e7af1.json +98 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/a9c29806556409fbfcd7622b876244caed085c63c70380dc6caacd162e6d05a9.json +132 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/b3142c5509452a15382cade5cb81324a26d1946d128a1b4342a143872f9354fe.json +149 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/b516a0820a66ae04229bfcb7f0463be0867f31a8dc1b875e57aba02b970a7a31.json +98 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/c175f8c35c81ebd2fb9e4bf4d2f1cc29f98b45006f59354c9f33ee780609d896.json +247 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/c950254390b901d475937c868e27e74960720fe65e2d8506bd39e30c634e619d.json +98 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/cac99fb54fa178e1a7f72e5212e1e99eff5fe72a1fa52f65fcee432bcf528b53.json +166 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/e38237abecf19ce5b9a92ed90723d2642a11b0f1ef189b1a1fc10b7ebcd3d4a4.json +88 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/e58e933def9b7000d791c83f6660adbecac59ab61e54f8d855a52d80200eb929.json +292 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/f8088377a1049850b0ec1acabf09da8504fb1f194479cc43ce4c31db3895afcd.json +176 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/fc2ccb6edbe2020010e036a69e7ece3ab3f007c9a4fed39066d6792d332e65af.json +142 -0
- oto_cli-1.0.0/oto/tools/.cache/notion/ff117c74176f8fc26aba7f06649c7794dc4a0c51194033f453b16c8af8ac4201.json +36 -0
- oto_cli-1.0.0/oto/tools/__init__.py +1 -0
- oto_cli-1.0.0/oto/tools/anthropic/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/anthropic/client.py +354 -0
- oto_cli-1.0.0/oto/tools/anthropic_batch/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/anthropic_batch/client.py +352 -0
- oto_cli-1.0.0/oto/tools/apollo/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/apollo/client.py +191 -0
- oto_cli-1.0.0/oto/tools/attio/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/attio/client.py +242 -0
- oto_cli-1.0.0/oto/tools/audio/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/audio/client.py +116 -0
- oto_cli-1.0.0/oto/tools/browser/__init__.py +26 -0
- oto_cli-1.0.0/oto/tools/browser/crunchbase.py +423 -0
- oto_cli-1.0.0/oto/tools/browser/g2.py +236 -0
- oto_cli-1.0.0/oto/tools/browser/indeed.py +282 -0
- oto_cli-1.0.0/oto/tools/browser/linkedin.py +821 -0
- oto_cli-1.0.0/oto/tools/browser/pappers.py +344 -0
- oto_cli-1.0.0/oto/tools/clearbit/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/clearbit/client.py +126 -0
- oto_cli-1.0.0/oto/tools/collective/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/collective/client.py +333 -0
- oto_cli-1.0.0/oto/tools/common/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/common/rate_limiter.py +457 -0
- oto_cli-1.0.0/oto/tools/figma/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/figma/client.py +254 -0
- oto_cli-1.0.0/oto/tools/folk/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/folk/client.py +203 -0
- oto_cli-1.0.0/oto/tools/gemini/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/gemini/client.py +264 -0
- oto_cli-1.0.0/oto/tools/google/__init__.py +1 -0
- oto_cli-1.0.0/oto/tools/google/calendar/__init__.py +0 -0
- oto_cli-1.0.0/oto/tools/google/calendar/lib/__init__.py +0 -0
- oto_cli-1.0.0/oto/tools/google/calendar/lib/calendar_client.py +155 -0
- oto_cli-1.0.0/oto/tools/google/credentials.py +177 -0
- oto_cli-1.0.0/oto/tools/google/docs/get_section.py +53 -0
- oto_cli-1.0.0/oto/tools/google/docs/insert_section.py +56 -0
- oto_cli-1.0.0/oto/tools/google/docs/insert_text.py +99 -0
- oto_cli-1.0.0/oto/tools/google/docs/lib/__init__.py +0 -0
- oto_cli-1.0.0/oto/tools/google/docs/lib/docs_client.py +341 -0
- oto_cli-1.0.0/oto/tools/google/docs/list_headings.py +44 -0
- oto_cli-1.0.0/oto/tools/google/docs/move_section.py +37 -0
- oto_cli-1.0.0/oto/tools/google/docs/replace_section.py +47 -0
- oto_cli-1.0.0/oto/tools/google/docs/sync/__init__.py +1 -0
- oto_cli-1.0.0/oto/tools/google/docs/sync/gdoc_sync.py +427 -0
- oto_cli-1.0.0/oto/tools/google/drive/README.md +308 -0
- oto_cli-1.0.0/oto/tools/google/drive/check_quota.py +31 -0
- oto_cli-1.0.0/oto/tools/google/drive/copy_file.py +76 -0
- oto_cli-1.0.0/oto/tools/google/drive/create_folder.py +58 -0
- oto_cli-1.0.0/oto/tools/google/drive/download_file.py +60 -0
- oto_cli-1.0.0/oto/tools/google/drive/export_doc.py +64 -0
- oto_cli-1.0.0/oto/tools/google/drive/export_slides.py +95 -0
- oto_cli-1.0.0/oto/tools/google/drive/extract_slides_content.py +113 -0
- oto_cli-1.0.0/oto/tools/google/drive/lib/drive_client.py +454 -0
- oto_cli-1.0.0/oto/tools/google/drive/list_files.py +97 -0
- oto_cli-1.0.0/oto/tools/google/drive/list_shared_drives.py +32 -0
- oto_cli-1.0.0/oto/tools/google/drive/move_file.py +57 -0
- oto_cli-1.0.0/oto/tools/google/drive/requirements.txt +4 -0
- oto_cli-1.0.0/oto/tools/google/drive/tool.yaml +210 -0
- oto_cli-1.0.0/oto/tools/google/drive/upload_file.py +90 -0
- oto_cli-1.0.0/oto/tools/google/gmail/__init__.py +1 -0
- oto_cli-1.0.0/oto/tools/google/gmail/get_message.py +33 -0
- oto_cli-1.0.0/oto/tools/google/gmail/lib/__init__.py +1 -0
- oto_cli-1.0.0/oto/tools/google/gmail/lib/gmail_client.py +385 -0
- oto_cli-1.0.0/oto/tools/google/gmail/list_messages.py +37 -0
- oto_cli-1.0.0/oto/tools/google/gmail/requirements.txt +3 -0
- oto_cli-1.0.0/oto/tools/google/gmail/search.py +34 -0
- oto_cli-1.0.0/oto/tools/google/gmail/send.py +39 -0
- oto_cli-1.0.0/oto/tools/google/gmail/tool.yaml +107 -0
- oto_cli-1.0.0/oto/tools/google/keep/__init__.py +0 -0
- oto_cli-1.0.0/oto/tools/google/keep/create_note.py +42 -0
- oto_cli-1.0.0/oto/tools/google/keep/get_master_token.py +101 -0
- oto_cli-1.0.0/oto/tools/google/keep/get_note.py +33 -0
- oto_cli-1.0.0/oto/tools/google/keep/lib/__init__.py +0 -0
- oto_cli-1.0.0/oto/tools/google/keep/lib/keep_client.py +273 -0
- oto_cli-1.0.0/oto/tools/google/keep/list_notes.py +42 -0
- oto_cli-1.0.0/oto/tools/google/keep/search.py +34 -0
- oto_cli-1.0.0/oto/tools/google/sheets/create_sheet_direct.py +157 -0
- oto_cli-1.0.0/oto/tools/google/sheets/create_sheet_from_csv.py +167 -0
- oto_cli-1.0.0/oto/tools/google/sheets/create_sheet_in_folder.py +165 -0
- oto_cli-1.0.0/oto/tools/google/sheets/create_sheet_via_drive.py +157 -0
- oto_cli-1.0.0/oto/tools/google/sheets/tool.yaml +74 -0
- oto_cli-1.0.0/oto/tools/google/slides/.folders +19 -0
- oto_cli-1.0.0/oto/tools/google/slides/321-LAYOUTS.md +203 -0
- oto_cli-1.0.0/oto/tools/google/slides/README.md +210 -0
- oto_cli-1.0.0/oto/tools/google/slides/USAGE-EDIT.md +626 -0
- oto_cli-1.0.0/oto/tools/google/slides/USAGE.md +158 -0
- oto_cli-1.0.0/oto/tools/google/slides/create-demo-presentation.py +348 -0
- oto_cli-1.0.0/oto/tools/google/slides/generate_slides.py +437 -0
- oto_cli-1.0.0/oto/tools/google/slides/lib/__init__.py +1 -0
- oto_cli-1.0.0/oto/tools/google/slides/lib/content_filler.py +579 -0
- oto_cli-1.0.0/oto/tools/google/slides/lib/layout_mappings.py +182 -0
- oto_cli-1.0.0/oto/tools/google/slides/lib/slides_client.py +1239 -0
- oto_cli-1.0.0/oto/tools/google/slides/requirements.txt +5 -0
- oto_cli-1.0.0/oto/tools/google/slides/test-copy-and-edit.py +187 -0
- oto_cli-1.0.0/oto/tools/google/slides/test-copy-slide.py +148 -0
- oto_cli-1.0.0/oto/tools/google/slides/test-edit.py +183 -0
- oto_cli-1.0.0/oto/tools/google/slides/tool.yaml +37 -0
- oto_cli-1.0.0/oto/tools/groq/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/groq/client.py +165 -0
- oto_cli-1.0.0/oto/tools/hithorizons/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/hithorizons/client.py +168 -0
- oto_cli-1.0.0/oto/tools/hunter/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/hunter/client.py +104 -0
- oto_cli-1.0.0/oto/tools/kaspr/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/kaspr/client.py +80 -0
- oto_cli-1.0.0/oto/tools/lemlist/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/lemlist/client.py +486 -0
- oto_cli-1.0.0/oto/tools/mistral/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/mistral/client.py +149 -0
- oto_cli-1.0.0/oto/tools/naf/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/naf/suggester.py +140 -0
- oto_cli-1.0.0/oto/tools/notion/README.md +310 -0
- oto_cli-1.0.0/oto/tools/notion/append_blocks.py +204 -0
- oto_cli-1.0.0/oto/tools/notion/append_blocks_chunked.py +296 -0
- oto_cli-1.0.0/oto/tools/notion/count_database_entries.py +47 -0
- oto_cli-1.0.0/oto/tools/notion/create_database_from_csv.py +269 -0
- oto_cli-1.0.0/oto/tools/notion/create_page.py +65 -0
- oto_cli-1.0.0/oto/tools/notion/get_database.py +67 -0
- oto_cli-1.0.0/oto/tools/notion/get_page.py +78 -0
- oto_cli-1.0.0/oto/tools/notion/known-pages.md +75 -0
- oto_cli-1.0.0/oto/tools/notion/lib/markdown_converter.py +287 -0
- oto_cli-1.0.0/oto/tools/notion/lib/notion_client.py +313 -0
- oto_cli-1.0.0/oto/tools/notion/list_teamspaces.py +244 -0
- oto_cli-1.0.0/oto/tools/notion/notion +122 -0
- oto_cli-1.0.0/oto/tools/notion/query_database.py +77 -0
- oto_cli-1.0.0/oto/tools/notion/requirements.txt +1 -0
- oto_cli-1.0.0/oto/tools/notion/search.py +93 -0
- oto_cli-1.0.0/oto/tools/notion/tool.yaml +235 -0
- oto_cli-1.0.0/oto/tools/notion/update_page.py +65 -0
- oto_cli-1.0.0/oto/tools/pennylane/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/pennylane/client.py +386 -0
- oto_cli-1.0.0/oto/tools/phantombuster/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/phantombuster/client.py +177 -0
- oto_cli-1.0.0/oto/tools/resend/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/resend/client.py +149 -0
- oto_cli-1.0.0/oto/tools/serpapi/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/serpapi/client.py +128 -0
- oto_cli-1.0.0/oto/tools/serper/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/serper/client.py +210 -0
- oto_cli-1.0.0/oto/tools/sirene/__init__.py +34 -0
- oto_cli-1.0.0/oto/tools/sirene/client.py +474 -0
- oto_cli-1.0.0/oto/tools/sirene/data/naf_codes.txt +732 -0
- oto_cli-1.0.0/oto/tools/sirene/entreprises.py +175 -0
- oto_cli-1.0.0/oto/tools/sirene/stock.py +377 -0
- oto_cli-1.0.0/oto/tools/slack/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/slack/client.py +202 -0
- oto_cli-1.0.0/oto/tools/unsplash/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/unsplash/client.py +197 -0
- oto_cli-1.0.0/oto/tools/whatsapp/__init__.py +3 -0
- oto_cli-1.0.0/oto/tools/whatsapp/client.py +68 -0
- oto_cli-1.0.0/oto/tools/whatsapp/node/package-lock.json +1564 -0
- oto_cli-1.0.0/oto/tools/whatsapp/node/package.json +11 -0
- oto_cli-1.0.0/oto/tools/whatsapp/node/whatsapp.mjs +357 -0
- oto_cli-1.0.0/oto/tools/wttj/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/wttj/client.py +251 -0
- oto_cli-1.0.0/oto/tools/zerobounce/__init__.py +5 -0
- oto_cli-1.0.0/oto/tools/zerobounce/client.py +93 -0
- oto_cli-1.0.0/pyproject.toml +59 -0
- oto_cli-1.0.0/skills/oto-anthropic/SKILL.md +38 -0
- oto_cli-1.0.0/skills/oto-browser/SKILL.md +103 -0
- oto_cli-1.0.0/skills/oto-cli/SKILL.md +100 -0
- oto_cli-1.0.0/skills/oto-enrichment/SKILL.md +60 -0
- oto_cli-1.0.0/skills/oto-google/SKILL.md +83 -0
- oto_cli-1.0.0/skills/oto-notion/SKILL.md +35 -0
- oto_cli-1.0.0/skills/oto-pennylane/SKILL.md +42 -0
- oto_cli-1.0.0/skills/oto-search/SKILL.md +29 -0
- oto_cli-1.0.0/skills/oto-sirene/SKILL.md +75 -0
- oto_cli-1.0.0/skills/oto-whatsapp/SKILL.md +33 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(mkdir:*)",
|
|
5
|
+
"Bash(source:*)",
|
|
6
|
+
"Bash(node:*)",
|
|
7
|
+
"Bash(oto whatsapp:*)",
|
|
8
|
+
"Bash(oto google:*)",
|
|
9
|
+
"Skill(claude-api)",
|
|
10
|
+
"Bash(npm list:*)",
|
|
11
|
+
"Bash(twilio:*)",
|
|
12
|
+
"Bash(ngrok:*)",
|
|
13
|
+
"Bash(sqlite3:*)",
|
|
14
|
+
"Bash(oto browser:*)",
|
|
15
|
+
"Bash(oto:*)",
|
|
16
|
+
"Bash(pipx list:*)",
|
|
17
|
+
"Bash(hatch build:*)"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
}
|
oto_cli-1.0.0/.gitignore
ADDED
oto_cli-1.0.0/CLAUDE.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Oto
|
|
2
|
+
|
|
3
|
+
CLI toolkit for AI agents — covers the long tail of SaaS APIs that don't have a CLI.
|
|
4
|
+
|
|
5
|
+
Repo: `AlexisLaporte/oto`. Package: `oto-cli` on PyPI. Command: `oto`.
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
- **CLI-first**: everything goes through `oto <command>`, no MCP, no server
|
|
10
|
+
- **For AI agents**: JSON on stdout, errors on stderr, composable with pipes
|
|
11
|
+
- **Modular**: each connector is a separate file, auto-discovered at startup
|
|
12
|
+
- **No over-engineering**: no plugin registry, no ABC, no MCP
|
|
13
|
+
|
|
14
|
+
## Stack
|
|
15
|
+
|
|
16
|
+
- Python 3.10+, Typer (CLI), Hatchling (build)
|
|
17
|
+
- Google APIs (auth, drive, docs, sheets, slides, gmail, keep)
|
|
18
|
+
- o-browser (browser automation, Patchright) — optional
|
|
19
|
+
- Requests (HTTP), python-dotenv (secrets)
|
|
20
|
+
|
|
21
|
+
## Architecture
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
oto/
|
|
25
|
+
├── oto/
|
|
26
|
+
│ ├── cli.py # Dynamic command discovery + main()
|
|
27
|
+
│ ├── config.py # Secrets 3-tier (.otomata/secrets.env)
|
|
28
|
+
│ ├── commands/ # 1 file = 1 sub-command (auto-discovered)
|
|
29
|
+
│ │ ├── google.py # drive, docs, sheets, slides, gmail, calendar, auth
|
|
30
|
+
│ │ ├── notion.py # search, page, database
|
|
31
|
+
│ │ ├── browser.py # linkedin, crunchbase, pappers, indeed, g2
|
|
32
|
+
│ │ ├── sirene.py # SIRENE API (search, get, stock)
|
|
33
|
+
│ │ ├── search.py # web, news (serper)
|
|
34
|
+
│ │ ├── enrichment.py # kaspr, hunter, lemlist
|
|
35
|
+
│ │ ├── pennylane.py # accounting
|
|
36
|
+
│ │ ├── anthropic.py # usage, cost, summary
|
|
37
|
+
│ │ ├── company.py # SIREN lookup multi-source
|
|
38
|
+
│ │ ├── whatsapp.py # WhatsApp messaging
|
|
39
|
+
│ │ └── skills.py # Claude Code skills (enable/disable)
|
|
40
|
+
│ └── tools/ # API clients
|
|
41
|
+
│ ├── google/ # gmail, drive, docs, sheets, slides, calendar, keep
|
|
42
|
+
│ ├── notion/ # pages, databases, search
|
|
43
|
+
│ ├── browser/ # linkedin, crunchbase, pappers, indeed, g2
|
|
44
|
+
│ ├── whatsapp/ # Node.js bridge (whatsapp-web.js)
|
|
45
|
+
│ ├── sirene/ # INSEE SIRENE API
|
|
46
|
+
│ ├── serper/ # Google search (web, news)
|
|
47
|
+
│ ├── anthropic/ # Admin API (usage, costs)
|
|
48
|
+
│ ├── pennylane/ # Accounting
|
|
49
|
+
│ ├── kaspr/, hunter/, lemlist/ # Enrichment & outreach
|
|
50
|
+
│ └── folk/, slack/, resend/ # CRM & messaging
|
|
51
|
+
├── skills/ # Claude Code skills
|
|
52
|
+
│ └── oto-*/SKILL.md # LLM instruction manuals
|
|
53
|
+
└── pyproject.toml # entry point: oto = "oto.cli:main"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Adding a new connector
|
|
57
|
+
|
|
58
|
+
A connector = 3 files:
|
|
59
|
+
|
|
60
|
+
1. **`commands/myservice.py`** — Typer app, exports `app`
|
|
61
|
+
2. **`tools/myservice/`** — API client(s)
|
|
62
|
+
3. **`skills/oto-myservice/SKILL.md`** — LLM instructions
|
|
63
|
+
|
|
64
|
+
See `docs/create-connector.md` for details.
|
|
65
|
+
|
|
66
|
+
## Command pattern
|
|
67
|
+
|
|
68
|
+
Each `commands/*.py` file:
|
|
69
|
+
```python
|
|
70
|
+
import typer
|
|
71
|
+
import json
|
|
72
|
+
from typing import Optional
|
|
73
|
+
|
|
74
|
+
app = typer.Typer(help="My service description")
|
|
75
|
+
|
|
76
|
+
@app.command("do-thing")
|
|
77
|
+
def do_thing(
|
|
78
|
+
query: str = typer.Argument(..., help="What to do"),
|
|
79
|
+
max_results: int = typer.Option(20, "--max-results", "-n"),
|
|
80
|
+
):
|
|
81
|
+
"""Do a thing."""
|
|
82
|
+
from oto.tools.myservice.client import MyServiceClient
|
|
83
|
+
client = MyServiceClient()
|
|
84
|
+
results = client.do_thing(query=query, max_results=max_results)
|
|
85
|
+
print(json.dumps(results, indent=2))
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Key rules:
|
|
89
|
+
- `app = typer.Typer()` exported, auto-discovered by `cli.py`
|
|
90
|
+
- Tool imports **inside functions** (lazy) so the CLI stays fast
|
|
91
|
+
- Always `print(json.dumps(..., indent=2))` for output
|
|
92
|
+
- Missing secrets raise `ValueError`, caught by `main()` → clean stderr message
|
|
93
|
+
|
|
94
|
+
## Secrets
|
|
95
|
+
|
|
96
|
+
3-tier resolution (first found wins):
|
|
97
|
+
1. Environment variables
|
|
98
|
+
2. `.otomata/secrets.env` in project directory (walks up 4 levels)
|
|
99
|
+
3. `~/.otomata/secrets.env` (user-level)
|
|
100
|
+
|
|
101
|
+
## Google OAuth
|
|
102
|
+
|
|
103
|
+
Tokens stored in `~/.otomata/google-oauth-token-{name}.json`.
|
|
104
|
+
|
|
105
|
+
Add an account: `oto google auth <name>` — opens browser for OAuth flow.
|
|
106
|
+
List accounts: `oto google auth --list`.
|
|
107
|
+
|
|
108
|
+
## Skills (Claude Code)
|
|
109
|
+
|
|
110
|
+
Skills = SKILL.md files in `skills/oto-*/`, symlinked to `~/.claude/skills/`.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
oto skills list # see status
|
|
114
|
+
oto skills enable --all # enable all
|
|
115
|
+
oto skills enable oto-google # enable one
|
|
116
|
+
oto skills disable oto-pennylane # disable one
|
|
117
|
+
```
|
oto_cli-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Alexis Laporte
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
oto_cli-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oto-cli
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: CLI toolkit for AI agents — covers the long tail of SaaS APIs that don't have a CLI
|
|
5
|
+
Project-URL: Repository, https://github.com/AlexisLaporte/oto
|
|
6
|
+
Author: Alexis Laporte
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: ai-agents,api,automation,cli,llm
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
16
|
+
Requires-Dist: requests>=2.28.0
|
|
17
|
+
Requires-Dist: typer>=0.9.0
|
|
18
|
+
Provides-Extra: all
|
|
19
|
+
Requires-Dist: anthropic>=0.40.0; extra == 'all'
|
|
20
|
+
Requires-Dist: gkeepapi>=0.16.0; extra == 'all'
|
|
21
|
+
Requires-Dist: google-api-python-client>=2.0.0; extra == 'all'
|
|
22
|
+
Requires-Dist: google-auth-oauthlib>=1.0.0; extra == 'all'
|
|
23
|
+
Requires-Dist: google-auth>=2.0.0; extra == 'all'
|
|
24
|
+
Requires-Dist: o-browser; extra == 'all'
|
|
25
|
+
Requires-Dist: pandas>=1.5.0; extra == 'all'
|
|
26
|
+
Requires-Dist: pyarrow>=10.0.0; extra == 'all'
|
|
27
|
+
Provides-Extra: anthropic
|
|
28
|
+
Requires-Dist: anthropic>=0.40.0; extra == 'anthropic'
|
|
29
|
+
Provides-Extra: browser
|
|
30
|
+
Requires-Dist: o-browser; extra == 'browser'
|
|
31
|
+
Provides-Extra: google
|
|
32
|
+
Requires-Dist: gkeepapi>=0.16.0; extra == 'google'
|
|
33
|
+
Requires-Dist: google-api-python-client>=2.0.0; extra == 'google'
|
|
34
|
+
Requires-Dist: google-auth-oauthlib>=1.0.0; extra == 'google'
|
|
35
|
+
Requires-Dist: google-auth>=2.0.0; extra == 'google'
|
|
36
|
+
Provides-Extra: stock
|
|
37
|
+
Requires-Dist: pandas>=1.5.0; extra == 'stock'
|
|
38
|
+
Requires-Dist: pyarrow>=10.0.0; extra == 'stock'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# oto — CLI toolkit for AI agents
|
|
42
|
+
|
|
43
|
+
Your LLM already uses `gh` for GitHub, `aws` for AWS, `gcloud` for GCP.
|
|
44
|
+
**oto** covers the long tail — the SaaS products that don't have a CLI.
|
|
45
|
+
|
|
46
|
+
Each connector ships with a **SKILL.md** — an instruction manual that teaches your AI agent how to use it. Run `oto skills enable --all` and your Claude Code / Cursor / Aider gets instant context on 15+ APIs.
|
|
47
|
+
|
|
48
|
+
## Why CLI over MCP?
|
|
49
|
+
|
|
50
|
+
| | CLI | MCP |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| Token cost | ~80 tokens (prompt + `--help`) | 4-32x more (full schema in context) |
|
|
53
|
+
| Reliability | 100% | ~72% ([source](https://scalekit.com)) |
|
|
54
|
+
| Setup | `pipx install oto-cli` | Server + transport + config |
|
|
55
|
+
| Composability | Pipes: `oto sirene search "fintech" \| jq '.[]'` | None |
|
|
56
|
+
| Works with | Every LLM, every framework | MCP-compatible clients only |
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Standalone CLI
|
|
62
|
+
pipx install oto-cli
|
|
63
|
+
|
|
64
|
+
# With specific connectors
|
|
65
|
+
pipx install "oto-cli[google,browser]"
|
|
66
|
+
|
|
67
|
+
# All connectors
|
|
68
|
+
pipx install "oto-cli[all]"
|
|
69
|
+
|
|
70
|
+
# Development
|
|
71
|
+
git clone https://github.com/AlexisLaporte/oto.git
|
|
72
|
+
cd oto && pip install -e ".[all]"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Connectors
|
|
76
|
+
|
|
77
|
+
| Command | What it does | Extra |
|
|
78
|
+
|---------|-------------|-------|
|
|
79
|
+
| `oto google` | Gmail, Drive, Docs, Sheets, Slides, Calendar | `google` |
|
|
80
|
+
| `oto browser` | LinkedIn, Crunchbase, Pappers, Indeed, G2 | `browser` |
|
|
81
|
+
| `oto notion` | Search, pages, databases | — |
|
|
82
|
+
| `oto sirene` | French company data (INSEE SIRENE) | — |
|
|
83
|
+
| `oto search` | Web & news search (Serper/Google) | — |
|
|
84
|
+
| `oto enrichment` | Contact enrichment (Kaspr, Hunter, Lemlist) | — |
|
|
85
|
+
| `oto pennylane` | Accounting (Pennylane API) | — |
|
|
86
|
+
| `oto anthropic` | API usage & cost tracking | `anthropic` |
|
|
87
|
+
| `oto whatsapp` | Send & read WhatsApp messages | — |
|
|
88
|
+
| `oto folk` | Folk CRM (contacts, companies, deals) | — |
|
|
89
|
+
| `oto company` | French company lookup (multi-source) | — |
|
|
90
|
+
| `oto audio` | Audio recording, transcription, summaries | — |
|
|
91
|
+
|
|
92
|
+
Connectors without an "Extra" only need `requests` (included in base install).
|
|
93
|
+
|
|
94
|
+
## Quick start
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Configure secrets
|
|
98
|
+
mkdir -p ~/.otomata
|
|
99
|
+
cat > ~/.otomata/secrets.env << 'EOF'
|
|
100
|
+
SERPER_API_KEY=xxx
|
|
101
|
+
NOTION_API_KEY=secret_xxx
|
|
102
|
+
SIRENE_API_KEY=xxx
|
|
103
|
+
EOF
|
|
104
|
+
|
|
105
|
+
# Check config
|
|
106
|
+
oto config
|
|
107
|
+
|
|
108
|
+
# Search the web
|
|
109
|
+
oto search web "AI agents 2026"
|
|
110
|
+
|
|
111
|
+
# Google OAuth setup (per account)
|
|
112
|
+
oto google auth myaccount
|
|
113
|
+
oto google gmail-search "from:bob" -a myaccount
|
|
114
|
+
|
|
115
|
+
# Browse LinkedIn
|
|
116
|
+
oto browser linkedin profile https://linkedin.com/in/someone
|
|
117
|
+
|
|
118
|
+
# French company data
|
|
119
|
+
oto sirene search "fintech"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Skills for AI agents
|
|
123
|
+
|
|
124
|
+
The killer feature: each connector comes with a SKILL.md that teaches your LLM how to use it.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Enable all skills for Claude Code
|
|
128
|
+
oto skills enable --all
|
|
129
|
+
|
|
130
|
+
# Or pick specific ones
|
|
131
|
+
oto skills enable oto-google
|
|
132
|
+
oto skills enable oto-search
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Once enabled, your AI agent sees these instructions in its context and knows exactly which `oto` commands to use, with what arguments, and what output to expect.
|
|
136
|
+
|
|
137
|
+
## Create your own connector
|
|
138
|
+
|
|
139
|
+
A connector is 3 files:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
oto/commands/myservice.py # CLI commands (Typer app)
|
|
143
|
+
oto/tools/myservice/ # API client
|
|
144
|
+
skills/oto-myservice/SKILL.md # LLM instructions
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
See [docs/create-connector.md](docs/create-connector.md) for the full guide.
|
|
148
|
+
|
|
149
|
+
## How it works
|
|
150
|
+
|
|
151
|
+
**Auto-discovery** — `cli.py` scans `commands/` at startup. Any Python file exporting a Typer `app` becomes a sub-command. No registry, no config. Drop a file, it appears in `oto --help`.
|
|
152
|
+
|
|
153
|
+
**Three types of connectors** (same CLI contract: JSON stdout, lazy imports, `get_secret()`):
|
|
154
|
+
- **API** — call REST APIs via `requests`. Each client handles auth/pagination/rate-limiting as the API requires. (notion, sirene, search, pennylane, folk...)
|
|
155
|
+
- **Browser** — automate a real browser for sites without an API. Async, require `oto-cli[browser]`. (linkedin, crunchbase, pappers, indeed, g2)
|
|
156
|
+
- **SDK** — use an official client library. Currently Google Workspace via `google-api-python-client` + OAuth2. Require `oto-cli[google]`.
|
|
157
|
+
|
|
158
|
+
**Secrets** — 3-tier resolution (first found wins):
|
|
159
|
+
1. Environment variables
|
|
160
|
+
2. `.otomata/secrets.env` in project directory (walks up 4 levels)
|
|
161
|
+
3. `~/.otomata/secrets.env` (user-level)
|
|
162
|
+
|
|
163
|
+
**Output contract** — every command prints JSON to stdout, errors to stderr. Composable with `jq`, pipes, scripts.
|
|
164
|
+
|
|
165
|
+
**Lazy imports** — tool clients are imported inside functions, so the CLI starts fast regardless of how many connectors are installed.
|
|
166
|
+
|
|
167
|
+
See [docs/concepts.md](docs/concepts.md) for the full architecture guide.
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT
|
oto_cli-1.0.0/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# oto — CLI toolkit for AI agents
|
|
2
|
+
|
|
3
|
+
Your LLM already uses `gh` for GitHub, `aws` for AWS, `gcloud` for GCP.
|
|
4
|
+
**oto** covers the long tail — the SaaS products that don't have a CLI.
|
|
5
|
+
|
|
6
|
+
Each connector ships with a **SKILL.md** — an instruction manual that teaches your AI agent how to use it. Run `oto skills enable --all` and your Claude Code / Cursor / Aider gets instant context on 15+ APIs.
|
|
7
|
+
|
|
8
|
+
## Why CLI over MCP?
|
|
9
|
+
|
|
10
|
+
| | CLI | MCP |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Token cost | ~80 tokens (prompt + `--help`) | 4-32x more (full schema in context) |
|
|
13
|
+
| Reliability | 100% | ~72% ([source](https://scalekit.com)) |
|
|
14
|
+
| Setup | `pipx install oto-cli` | Server + transport + config |
|
|
15
|
+
| Composability | Pipes: `oto sirene search "fintech" \| jq '.[]'` | None |
|
|
16
|
+
| Works with | Every LLM, every framework | MCP-compatible clients only |
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Standalone CLI
|
|
22
|
+
pipx install oto-cli
|
|
23
|
+
|
|
24
|
+
# With specific connectors
|
|
25
|
+
pipx install "oto-cli[google,browser]"
|
|
26
|
+
|
|
27
|
+
# All connectors
|
|
28
|
+
pipx install "oto-cli[all]"
|
|
29
|
+
|
|
30
|
+
# Development
|
|
31
|
+
git clone https://github.com/AlexisLaporte/oto.git
|
|
32
|
+
cd oto && pip install -e ".[all]"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Connectors
|
|
36
|
+
|
|
37
|
+
| Command | What it does | Extra |
|
|
38
|
+
|---------|-------------|-------|
|
|
39
|
+
| `oto google` | Gmail, Drive, Docs, Sheets, Slides, Calendar | `google` |
|
|
40
|
+
| `oto browser` | LinkedIn, Crunchbase, Pappers, Indeed, G2 | `browser` |
|
|
41
|
+
| `oto notion` | Search, pages, databases | — |
|
|
42
|
+
| `oto sirene` | French company data (INSEE SIRENE) | — |
|
|
43
|
+
| `oto search` | Web & news search (Serper/Google) | — |
|
|
44
|
+
| `oto enrichment` | Contact enrichment (Kaspr, Hunter, Lemlist) | — |
|
|
45
|
+
| `oto pennylane` | Accounting (Pennylane API) | — |
|
|
46
|
+
| `oto anthropic` | API usage & cost tracking | `anthropic` |
|
|
47
|
+
| `oto whatsapp` | Send & read WhatsApp messages | — |
|
|
48
|
+
| `oto folk` | Folk CRM (contacts, companies, deals) | — |
|
|
49
|
+
| `oto company` | French company lookup (multi-source) | — |
|
|
50
|
+
| `oto audio` | Audio recording, transcription, summaries | — |
|
|
51
|
+
|
|
52
|
+
Connectors without an "Extra" only need `requests` (included in base install).
|
|
53
|
+
|
|
54
|
+
## Quick start
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Configure secrets
|
|
58
|
+
mkdir -p ~/.otomata
|
|
59
|
+
cat > ~/.otomata/secrets.env << 'EOF'
|
|
60
|
+
SERPER_API_KEY=xxx
|
|
61
|
+
NOTION_API_KEY=secret_xxx
|
|
62
|
+
SIRENE_API_KEY=xxx
|
|
63
|
+
EOF
|
|
64
|
+
|
|
65
|
+
# Check config
|
|
66
|
+
oto config
|
|
67
|
+
|
|
68
|
+
# Search the web
|
|
69
|
+
oto search web "AI agents 2026"
|
|
70
|
+
|
|
71
|
+
# Google OAuth setup (per account)
|
|
72
|
+
oto google auth myaccount
|
|
73
|
+
oto google gmail-search "from:bob" -a myaccount
|
|
74
|
+
|
|
75
|
+
# Browse LinkedIn
|
|
76
|
+
oto browser linkedin profile https://linkedin.com/in/someone
|
|
77
|
+
|
|
78
|
+
# French company data
|
|
79
|
+
oto sirene search "fintech"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Skills for AI agents
|
|
83
|
+
|
|
84
|
+
The killer feature: each connector comes with a SKILL.md that teaches your LLM how to use it.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Enable all skills for Claude Code
|
|
88
|
+
oto skills enable --all
|
|
89
|
+
|
|
90
|
+
# Or pick specific ones
|
|
91
|
+
oto skills enable oto-google
|
|
92
|
+
oto skills enable oto-search
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Once enabled, your AI agent sees these instructions in its context and knows exactly which `oto` commands to use, with what arguments, and what output to expect.
|
|
96
|
+
|
|
97
|
+
## Create your own connector
|
|
98
|
+
|
|
99
|
+
A connector is 3 files:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
oto/commands/myservice.py # CLI commands (Typer app)
|
|
103
|
+
oto/tools/myservice/ # API client
|
|
104
|
+
skills/oto-myservice/SKILL.md # LLM instructions
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
See [docs/create-connector.md](docs/create-connector.md) for the full guide.
|
|
108
|
+
|
|
109
|
+
## How it works
|
|
110
|
+
|
|
111
|
+
**Auto-discovery** — `cli.py` scans `commands/` at startup. Any Python file exporting a Typer `app` becomes a sub-command. No registry, no config. Drop a file, it appears in `oto --help`.
|
|
112
|
+
|
|
113
|
+
**Three types of connectors** (same CLI contract: JSON stdout, lazy imports, `get_secret()`):
|
|
114
|
+
- **API** — call REST APIs via `requests`. Each client handles auth/pagination/rate-limiting as the API requires. (notion, sirene, search, pennylane, folk...)
|
|
115
|
+
- **Browser** — automate a real browser for sites without an API. Async, require `oto-cli[browser]`. (linkedin, crunchbase, pappers, indeed, g2)
|
|
116
|
+
- **SDK** — use an official client library. Currently Google Workspace via `google-api-python-client` + OAuth2. Require `oto-cli[google]`.
|
|
117
|
+
|
|
118
|
+
**Secrets** — 3-tier resolution (first found wins):
|
|
119
|
+
1. Environment variables
|
|
120
|
+
2. `.otomata/secrets.env` in project directory (walks up 4 levels)
|
|
121
|
+
3. `~/.otomata/secrets.env` (user-level)
|
|
122
|
+
|
|
123
|
+
**Output contract** — every command prints JSON to stdout, errors to stderr. Composable with `jq`, pipes, scripts.
|
|
124
|
+
|
|
125
|
+
**Lazy imports** — tool clients are imported inside functions, so the CLI starts fast regardless of how many connectors are installed.
|
|
126
|
+
|
|
127
|
+
See [docs/concepts.md](docs/concepts.md) for the full architecture guide.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
oto_cli-1.0.0/TODO.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# TODO / Roadmap
|
|
2
|
+
|
|
3
|
+
## Browser automation
|
|
4
|
+
|
|
5
|
+
### Multi-backend support
|
|
6
|
+
Currently using Patchright (undetectable Playwright). Consider adding alternative backends:
|
|
7
|
+
|
|
8
|
+
- **Vercel Agent-Browser** (https://github.com/vercel-labs/agent-browser)
|
|
9
|
+
- CLI Rust/Node, fast
|
|
10
|
+
- `snapshot` command returns accessibility tree (AI-friendly)
|
|
11
|
+
- Stateful across commands
|
|
12
|
+
- `--profile` for session persistence
|
|
13
|
+
- Installation: `npm install -g agent-browser`
|
|
14
|
+
|
|
15
|
+
Could be useful for AI agent workflows where we want structured DOM info rather than raw HTML/text.
|
|
16
|
+
|
|
17
|
+
- **Chrome DevTools MCP** (https://github.com/anthropics/chrome-devtools-mcp)
|
|
18
|
+
- 26 outils : navigation, input, debugging, network, performance, emulation
|
|
19
|
+
- Accès direct aux DevTools (console, network, DOM)
|
|
20
|
+
- Tests E2E déclaratifs en YAML
|
|
21
|
+
- Installation: `claude mcp add chrome-devtools npx chrome-devtools-mcp@latest`
|
|
22
|
+
|
|
23
|
+
Complémentaire à Patchright : utile pour debugging dev web, pas pour scraping (nécessite Chrome UI).
|
|
24
|
+
|
|
25
|
+
### Ideas
|
|
26
|
+
- [ ] Abstract backend selection in BrowserClient (patchright vs agent-browser)
|
|
27
|
+
- [ ] Add `snapshot()` method that returns structured accessibility tree (format AI-friendly)
|
|
28
|
+
- [ ] Évaluer Chrome DevTools MCP pour tests E2E (complémentaire à Patchright)
|
|
29
|
+
|
|
30
|
+
## Scrapers
|
|
31
|
+
|
|
32
|
+
- [x] Indeed jobs scraper
|
|
33
|
+
- [x] LinkedIn profile scraper
|
|
34
|
+
- [x] Crunchbase, Pappers, G2 scrapers
|
|
35
|
+
- [ ] Generic "login + navigate + extract" pattern
|
|
36
|
+
|
|
37
|
+
## Google tools
|
|
38
|
+
|
|
39
|
+
- [ ] Calendar integration
|
|
40
|
+
- [ ] Gmail (or use MCP server?)
|
|
41
|
+
|
|
42
|
+
## Notion tools
|
|
43
|
+
|
|
44
|
+
- [ ] Batch page creation
|
|
45
|
+
- [ ] Database sync with external sources
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Concepts
|
|
2
|
+
|
|
3
|
+
## Why oto exists
|
|
4
|
+
|
|
5
|
+
LLMs are good at using CLI tools — they were trained on billions of terminal interactions. For popular tools (`gh`, `aws`, `gcloud`, `docker`), the LLM already knows the commands.
|
|
6
|
+
|
|
7
|
+
But most SaaS products don't have a CLI. When an AI agent needs to interact with Notion, Pennylane, LinkedIn, or SIRENE, it has two options:
|
|
8
|
+
1. **MCP** — a protocol that puts the full API schema in the LLM's context window (expensive: 4-32x more tokens, 72% reliability)
|
|
9
|
+
2. **CLI** — a command-line tool the LLM calls via Bash (cheap: ~80 tokens, 100% reliability)
|
|
10
|
+
|
|
11
|
+
**oto is option 2.** One CLI, many connectors, each with an LLM instruction manual (SKILL.md).
|
|
12
|
+
|
|
13
|
+
## Architecture
|
|
14
|
+
|
|
15
|
+
### Auto-discovery
|
|
16
|
+
|
|
17
|
+
`cli.py` scans `oto/commands/` at startup. Any `.py` file that exports `app = typer.Typer()` becomes a sub-command:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
commands/google.py → oto google ...
|
|
21
|
+
commands/search.py → oto search ...
|
|
22
|
+
commands/stripe.py → oto stripe ... (you add this)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
No registry, no config. Drop a file, it works.
|
|
26
|
+
|
|
27
|
+
### Connector anatomy
|
|
28
|
+
|
|
29
|
+
A connector is 3 parts:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
commands/myservice.py # CLI layer (Typer commands)
|
|
33
|
+
tools/myservice/client.py # API client (business logic)
|
|
34
|
+
skills/oto-myservice/SKILL.md # LLM instructions
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Commands** define the CLI surface — arguments, options, help text. They import the tool client lazily (inside the function body) so the CLI starts fast.
|
|
38
|
+
|
|
39
|
+
**Tool clients** talk to the API. They use `get_secret()` for auth and return plain Python dicts/lists.
|
|
40
|
+
|
|
41
|
+
**Skills** are markdown files that teach the LLM how to use the connector. They get symlinked into `~/.claude/skills/` and appear in the agent's context.
|
|
42
|
+
|
|
43
|
+
### Connector types
|
|
44
|
+
|
|
45
|
+
There are 3 types of connectors. They differ in how the tool client talks to the service, but the CLI contract is always the same: JSON on stdout, lazy imports, `get_secret()` for auth.
|
|
46
|
+
|
|
47
|
+
**API connectors** — call a REST API via `requests`. Most connectors are this type. Auth, rate limiting, and pagination depend on the provider — each client handles it as the API requires.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
tools/serper/client.py → requests + X-API-KEY header
|
|
51
|
+
tools/notion/client.py → requests + Bearer token + cursor pagination
|
|
52
|
+
tools/pennylane/client.py → requests + Bearer token + retry on 429
|
|
53
|
+
tools/folk/client.py → requests + Bearer token + Retry-After header
|
|
54
|
+
tools/kaspr/client.py → requests + Bearer token
|
|
55
|
+
tools/hunter/client.py → requests + query param api_key
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Browser connectors** — automate a real browser (via [o-browser](https://github.com/AntMusic/o-browser)) for sites that don't have an API, or where the API is too limited. They inherit from `BrowserClient`, are async, and use context managers. Commands wrap them in `asyncio.run()`.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
tools/browser/linkedin.py → cookie auth, file-based rate limiting
|
|
62
|
+
tools/browser/crunchbase.py → cookie auth, session persistence
|
|
63
|
+
tools/browser/pappers.py → no auth, Cloudflare handling
|
|
64
|
+
tools/browser/indeed.py → no auth, multi-country
|
|
65
|
+
tools/browser/g2.py → no auth, review scraping
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Require the `browser` extra: `pip install oto-cli[browser]`.
|
|
69
|
+
|
|
70
|
+
**SDK connectors** — use an official SDK instead of raw HTTP. Currently only Google Workspace, which uses `google-api-python-client` with OAuth2 tokens stored in `~/.otomata/google-oauth-token-{name}.json`.
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
tools/google/gmail/ → google-api-python-client (OAuth2)
|
|
74
|
+
tools/google/drive/ → google-api-python-client (OAuth2)
|
|
75
|
+
tools/google/docs/ → google-api-python-client (OAuth2)
|
|
76
|
+
tools/google/calendar/ → google-api-python-client (OAuth2)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Require the `google` extra: `pip install oto-cli[google]`.
|
|
80
|
+
|
|
81
|
+
**There's no base class.** Each client implements what its API requires — the only shared contract is on the CLI side (JSON output, lazy imports, `get_secret()`).
|
|
82
|
+
|
|
83
|
+
### Secrets
|
|
84
|
+
|
|
85
|
+
3-tier resolution — first found wins:
|
|
86
|
+
|
|
87
|
+
| Priority | Location | Scope |
|
|
88
|
+
|----------|----------|-------|
|
|
89
|
+
| 1 | Environment variable | Session |
|
|
90
|
+
| 2 | `.otomata/secrets.env` (project dir, walks up 4 levels) | Project |
|
|
91
|
+
| 3 | `~/.otomata/secrets.env` | User |
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Setup
|
|
95
|
+
mkdir -p ~/.otomata
|
|
96
|
+
echo "SERPER_API_KEY=xxx" >> ~/.otomata/secrets.env
|
|
97
|
+
|
|
98
|
+
# Check
|
|
99
|
+
oto config
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
In code, `get_secret("SERPER_API_KEY")` resolves through all 3 tiers. If the key is missing, it raises a `ValueError` with instructions — caught by `main()` for a clean error message.
|
|
103
|
+
|
|
104
|
+
### Output contract
|
|
105
|
+
|
|
106
|
+
Every command prints JSON to stdout:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
oto search web "AI agents" | jq '.[0].title'
|
|
110
|
+
oto sirene search "fintech" | jq '.[] | .siren'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Errors go to stderr. Exit code 0 = success, 1 = error. This makes oto composable with standard Unix tools.
|
|
114
|
+
|
|
115
|
+
### Skills (SKILL.md)
|
|
116
|
+
|
|
117
|
+
A SKILL.md is a markdown file with YAML frontmatter:
|
|
118
|
+
|
|
119
|
+
```markdown
|
|
120
|
+
---
|
|
121
|
+
name: oto-search
|
|
122
|
+
description: Web and news search via Serper (Google)
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
# Search
|
|
126
|
+
Use `oto search` commands via Bash.
|
|
127
|
+
...
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
When symlinked to `~/.claude/skills/`, the LLM sees this file in its context and learns when and how to use the connector. The `description` field is what the LLM uses to decide if the skill is relevant.
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
oto skills enable oto-search # creates symlink
|
|
134
|
+
oto skills disable oto-search # removes symlink
|
|
135
|
+
oto skills list # shows status
|
|
136
|
+
```
|