Doramagic Project Pack · Human Manual
oto-cli
CLI for business automation — Google Workspace, browser scraping, company data, AI, CRM. For humans and AI agents.
Introduction to oto-cli
Related topics: Architecture and Auto-Discovery, Built-in Connectors Reference
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Architecture and Auto-Discovery, Built-in Connectors Reference
Introduction to oto-cli
oto-cli is a Python-based command-line tool maintained by Otomata Tech. It ships a unified oto entry point that aggregates several day-to-day utilities: configuration management, secret lookup, and a growing browser-automation toolkit. The current major release, v1.5.0, introduced plugin-based extension via Python entry-points, allowing optional browser clients to be installed as separate extras. Source: README.md:1-30
What `oto-cli` Solves
The tool consolidates internal scripts (previously scattered shell utilities, including legacy browser clients in /data/pro/veille/) into a single, discoverable, and installable package. It targets three main usage areas:
- Configuration management —
oto configsubcommands for inspecting and editing local config. - Secret retrieval —
oto config provider secretsresolves credentials from multiple backends (file, Scaleway, environment variables). - Browser automation —
oto browserdrives headless browsers against sites such as LinkedIn, Crunchbase, Pappers, Collective, WTTJ, and VivaTech.
Source: docs/installation.md:1-25 Source: docs/secrets.md:1-40
Command Discovery and Plugin Architecture
The root entry point is defined in cli.py. At startup, the CLI discovers its subcommands by globbing the oto/commands/ package directory: cli.py iterates over _commands_dir.glob("*.py") and imports each module that exposes a command definition. Source: cli.py:1-40
This in-package discovery is simple but limits extensibility: custom or client-specific connectors cannot be added from outside the package without modifying the source tree. Community discussion in issue #9 ("Isoler les connecteurs custom/client du core public via entry-points oto.commands") tracks the proposal to introduce a proper Python entry-point under the oto.commands group, which would let third-party packages register additional commands without forking the core. Source: cli.py:1-40
A precedent for this plugin model already exists in the browser subsystem. Starting with v1.5.0, oto browser vivatech is delivered as a separate plugin (o-browser-vivatech) that registers through the o_browser.sites entry-point group. Users opt in by installing the optional extra oto-cli[vivatech]. Source: pyproject.toml:1-60 Source: oto/tools/browser/__init__.py:1-30
┌──────────────────────────────────────────────────┐
│ oto (CLI entry) │
├──────────────────────────────────────────────────┤
│ cli.py ──► glob oto/commands/*.py │
│ ──► importlib entry-points │
│ (o_browser.sites, etc.) │
├──────────────────────────────────────────────────┤
│ oto/commands/ │ external plugin packages │
│ ────────────── │ ───────────────────────── │
│ config │ o-browser-vivatech │
│ browser (core) │ o-browser-<custom> │
│ tools │ │
└──────────────────────────────────────────────────┘
Configuration and Secrets
Configuration is read from a local config directory, and the secret-lookup subsystem is pluggable. As of the current release, oto config provider secrets <file|scaleway> exposes two first-class providers plus an environment-variable fallback. Internally, Otomata also relies on SOPS for secret management in its otomata-tech/secrets repository, but SOPS is not yet a first-class provider in the CLI. Issue #3 ("rework secrets côté CLI") tracks the planned expansion to a unified oto secrets lookup with scoped providers, including SOPS, OS keychain, and a clean precedence order between providers. Source: docs/secrets.md:1-60
Installation and Optional Extras
The package is installed from PyPI or from source via pip install oto-cli. Optional features are exposed as pip extras. The vivatech extra pulls in the VivaTech browser plugin:
pip install "oto-cli[vivatech]"
Each extra corresponds to a dependency group declared in pyproject.toml and to an external package that registers itself under a known entry-point. This pattern is the reference design for future command-level plugins once issue #9 lands. Source: pyproject.toml:1-80 Source: docs/installation.md:1-40
Project Conventions
- In-package commands live under
oto/commands/and are auto-loaded via glob. Source: oto/commands/__init__.py:1-20 - Browser clients are unit-style: a client knows how to fetch data from a single site but does not own "stop on seen" or deduplication logic, which is handled by the orchestrating command (as called out in issue #1 for the Collective and WTTJ clients). Source: oto/tools/browser/__init__.py:1-30
- Plugins register through Python entry-points; the
oto-clicore treats them as opt-in extensions rather than bundled dependencies.
Together these conventions define a CLI that is small in its core, explicit about what it ships, and extensible through standard packaging mechanisms.
Source: https://github.com/otomata-tech/oto-cli / Human Manual
Architecture and Auto-Discovery
Related topics: Introduction to oto-cli, Built-in Connectors Reference, Creating Custom Connectors
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Introduction to oto-cli, Built-in Connectors Reference, Creating Custom Connectors
Architecture and Auto-Discovery
oto-cli is a domain-oriented command-line toolkit organized around a small, explicit core and a directory-based convention for registering user-facing subcommands. The project follows a plugin-style architecture where the cli.py entry point bootstraps a Typer application and dynamically wires sub-apps discovered from two places: built-in command modules under oto/commands/ and external browser-site clients discovered via the o_browser.sites Python entry-point group.
Overall Architecture
The CLI is layered as follows:
- Entry point (
oto/cli.py) — defines the roottyper.Typerapp, sets up logging, configuration providers, and the global--verbose / --debugflags. It then mounts sub-apps for each discovered command. - Built-in commands (
oto/commands/) — each*.pyfile in this directory is treated as a command module exposing aapp: typer.Typerobject. These are loaded eagerly at startup viaimportlib. - Toolkit layer (
oto/tools/) — non-CLI utility code (browser clients, helpers, IO, scoring) consumed by commands. Tools are not auto-discovered as commands; they are imported explicitly. - Plugins (entry-points) — optional external packages, e.g.
o-browser-vivatech, that contribute browser-site clients under theo_browser.sitesgroup.
Source: oto/cli.py:1-80 and docs/concepts.md:1-60
Command Auto-Discovery via Glob
The primary auto-discovery mechanism is a pathlib glob over the oto/commands/ package. cli.py resolves _commands_dir = Path(__file__).parent / "commands" and iterates _commands_dir.glob("*.py"). For each module file it performs a dynamic importlib.import_module(f"oto.commands.{stem}") and, if the module exposes a top-level app attribute, mounts it under the root Typer application. Source: oto/cli.py:30-75
This convention has two consequences documented in the codebase:
- Drop-in extensibility inside the repo — adding a new command is as simple as creating a new file under
oto/commands/. No central registry must be edited. Source: docs/cli.md:1-40 - In-package limitation — discovery is scoped to files shipped inside the
oto.commandspackage itself. There is no native hook for third-party packages to inject commands unless they live next to the CLI source. This limitation is the subject of issue #9 ("Isoler les connecteurs custom/client du core public via entry-pointsoto.commands"), which proposes introducing anoto.commandsentry-point group analogous to the existingo_browser.sites. Source: community issue #9
The __init__.py of oto/commands/ is intentionally minimal — it only re-exports subpackages so the glob loader can find them. It does not register commands manually. Source: oto/commands/__init__.py:1-20
Plugin Auto-Discovery via Entry-Points
A second, narrower form of discovery is used for browser-site clients. Each browser client module lives under oto/tools/browser/ (for example linkedin, crunchbase, pappers) and exposes a uniform interface. The registry is populated by walking the o_browser.sites entry-point group declared in pyproject.toml, using importlib.metadata.entry_points(). Source: oto/tools/browser/__init__.py:1-60 and pyproject.toml:30-80
The release v1.5.0 introduced the first external consumer of this mechanism: the o-browser-vivatech package, installable as the optional extra oto-cli[vivatech]. After installation, the oto browser vivatech command becomes available without any change to oto-cli itself. Source: release notes v1.5.0
flowchart LR
A[oto/cli.py<br/>root Typer app] --> B[oto/commands/*.py<br/>glob + importlib]
A --> C[oto browser<br/>sub-app]
C --> D[oto/tools/browser/*<br/>built-in clients]
C --> E[o_browser.sites<br/>entry-points]
E --> F[o-browser-vivatech<br/>optional extra]Configuration and Secrets Wiring
Beyond commands, cli.py also wires the configuration system at startup. The oto config command exposes provider selection for secrets (file, scaleway) with environment-variable fallback. SOPS is mentioned in the community discussion (issue #3) as an internal-only provider that is not yet exposed as a first-class option in the public CLI. Source: docs/concepts.md:60-120 and community issue #3
The architecture therefore separates three concerns:
| Layer | Discovery mechanism | Mutability |
|---|---|---|
| Commands | Path.glob("*.py") over oto/commands/ | Editable in-repo only |
| Browser sites | importlib.metadata entry-points o_browser.sites | Extensible via pip extras |
| Secrets providers | Hard-coded list (file, scaleway) + env fallback | Configuration-time choice |
Source: oto/cli.py:80-140 and pyproject.toml:1-40
Practical Implications
For contributors adding commands, the path of least resistance remains placing a new *.py under oto/commands/ with a module-level app = typer.Typer(...). For maintainers distributing client-specific connectors outside the public core, the established pattern is the entry-point group, and issue #9 tracks generalizing that pattern from o_browser.sites to a generic oto.commands group. Source: docs/concepts.md:120-180 and community issue #9
Source: https://github.com/otomata-tech/oto-cli / Human Manual
Built-in Connectors Reference
Related topics: Architecture and Auto-Discovery, Creating Custom Connectors
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Architecture and Auto-Discovery, Creating Custom Connectors
Built-in Connectors Reference
The built-in connectors in oto-cli are the command modules shipped under oto/commands/. Each module exposes one or more Click subcommands that wrap an external API, headless-browser client, or local enrichment step. They form the *public core* of the CLI: every user who installs oto-cli gets them out of the box, and they are the baseline against which custom/client-specific connectors are contrasted (see issue #9).
Discovery Mechanism
oto/cli.py loads built-in connectors by globbing Python files in the oto/commands/ package:
# oto/cli.py (illustrative)
for _module_path in _commands_dir.glob("*.py"):
...
This means that **adding a built-in connector is as simple as dropping a new *.py file into oto/commands/. There is currently no entry-point registration for built-ins; that gap is exactly what issue #9 ("Isoler les connecteurs custom/client du core public via entry-points oto.commands") addresses — custom/client connectors cannot yet extend the core without forking. By contrast, browser site** connectors already use entry-points (o_browser.sites), as demonstrated by o-browser-vivatech in v1.5.0.
Source: oto/cli.py
Connector Catalog
The currently shipped built-in command modules are summarized below. Each module typically registers a Click group (e.g. oto browser …) that fans out into site- or action-specific subcommands.
| Module | Command group | Purpose |
|---|---|---|
oto/commands/browser.py | oto browser … | Headless-browser clients for external sites |
oto/commands/google.py | oto google … | Google APIs (e.g. Sheets/Drive helpers) |
oto/commands/notion.py | oto notion … | Notion API helpers |
oto/commands/serper.py | oto serper … | Serper.dev search API wrapper |
oto/commands/search.py | oto search … | Cross-provider search aggregator |
oto/commands/enrichment.py | oto enrichment … | Composite enrichment pipelines |
Source: oto/commands/browser.py, oto/commands/google.py, oto/commands/notion.py, oto/commands/serper.py, oto/commands/search.py, oto/commands/enrichment.py
Browser Connectors
The browser subsystem is the largest family of built-in connectors. oto/commands/browser.py exposes a generic oto browser <site> command that dispatches to per-site clients living in oto/tools/browser/. Out-of-the-box sites include LinkedIn, Crunchbase, and Pappers; Collective and WTTJ were migrated from legacy shell scripts into the same directory (issue #1). Each client is *unitary*: it does not implement "stop on seen" logic — that deduplication is layered on top by the caller.
Site connectors are pluggable: o-browser-vivatech is shipped as a separate package that registers itself via the o_browser.sites entry-point, so oto browser vivatech only appears when the optional extra oto-cli[vivatech] is installed (v1.5.0 release notes).
Source: oto/commands/browser.py
Search, Enrichment, and Knowledge Connectors
oto/commands/search.pyandoto/commands/serper.py:serperis a thin wrapper around the Serper.dev Google Search API;searchaggregates results across providers and normalizes output for downstream enrichment.oto/commands/enrichment.py: orchestrates multi-step enrichment by chaining search, browser, and knowledge connectors (Notion/Google) into reusable pipelines.oto/commands/google.pyandoto/commands/notion.py: target the Google Workspace and Notion APIs respectively, typically used to persist enrichment results into Sheets or Notion databases.
Source: oto/commands/search.py, oto/commands/serper.py, oto/commands/enrichment.py, oto/commands/google.py, oto/commands/notion.py
Configuration and Secrets
Built-in connectors share a common secrets-resolution layer. The command oto config provider secrets <file|scaleway> switches between two first-class providers — a local encrypted file provider and a Scaleway secret manager — with environment-variable fallback. SOPS (used internally by Otomata) is not yet exposed as a first-class provider; issue #3 ("rework secrets côté CLI") tracks the roadmap to add it and to scope lookups per connector so that, for example, serper only requests the SERPER_API_KEY while notion only requests the Notion token.
Until entry-point-based loading lands (issue #9), any custom connector that needs to live alongside the built-ins must either be vendored into oto/commands/ or shipped as a separate plugin using one of the existing entry-point groups such as o_browser.sites.
Source: oto/cli.py
Source: https://github.com/otomata-tech/oto-cli / Human Manual
Creating Custom Connectors
Related topics: Architecture and Auto-Discovery, Built-in Connectors Reference
Continue reading this section for the full explanation and source context.
Related Pages
Related topics: Architecture and Auto-Discovery, Built-in Connectors Reference
Creating Custom Connectors
Purpose and Scope
Custom connectors in oto-cli are Python modules that expose new sub-commands under the oto CLI. They allow teams to package client-specific or domain-specific automations (CRM scrapers, internal SaaS bridges, browser site clients, etc.) without modifying the public core. The current discovery mechanism lives entirely inside the package: at startup, the CLI scans a fixed directory and loads every module that matches a glob. Source: oto/cli.py documents this loop via _commands_dir.glob("*.py").
This page explains how a connector is structured today, where it must live to be picked up, and what changes are being discussed (entry-points) so that third-party connectors can ship independently of the core package.
Connector Structure Today
A connector is a single .py file under oto/commands/. The discovery contract is intentionally minimal:
- File name becomes the command name (without
.py). Source: oto/cli.py - The module exposes one or more Typer/Click callbacks decorated with
@app.command(...). Source: oto/commands/__init__.py - Shared runtime helpers (config loader, secret lookup, logger) are imported from sibling modules such as
config.pyandsecrets.py. Source: oto/commands/config.py and oto/commands/secrets.py
The package's __init__.py aggregates a shared Typer app and re-exports helpers so each connector file stays short. The pattern is repeated for every built-in connector (config, secrets, browser, etc.). Source: oto/commands/__init__.py
The official guidance file docs/create-connector.md walks through this same template: drop a file in oto/commands/, decorate a function with @app.command, and rely on the core CLI to wire it under oto <your-connector>. Source: docs/create-connector.md
Registration Flow
The current registration is filesystem-based rather than plugin-based. The CLI reads _commands_dir from the installed package, iterates *.py entries, imports each module, and lets the decorators register commands on the shared app object.
flowchart LR
A[oto CLI start] --> B[Resolve oto/commands dir]
B --> C[Glob *.py files]
C --> D[Import each module]
D --> E[Decorators register on shared Typer app]
E --> F[oto <cmd> available]This simple model has a limitation that the community has flagged: it does not allow a connector to live outside the installed package. Source: oto/cli.py shows there is no entry-point lookup; only files physically present in the package directory are loaded. As discussed in issue #9, isolating custom/client connectors from the public core via entry-points oto.commands is the proposed solution so a client-specific connector can ship as its own distribution and still be discovered at runtime. The latest release v1.5.0 already demonstrates this pattern for browser sites through the o_browser.sites entry-point consumed by the oto browser namespace. Source: pyproject.toml
Best Practices and Conventions
When authoring a connector today, follow the conventions enforced by the existing built-ins:
| Concern | Convention | Reference |
|---|---|---|
| File location | oto/commands/<name>.py | oto/cli.py |
| Command object | Reuse shared Typer app | oto/commands/__init__.py |
| Configuration | Read via oto/commands/config.py helpers | oto/commands/config.py |
| Secrets | Read via oto/commands/secrets.py providers | oto/commands/secrets.py |
| Optional deps | Declared as extras in pyproject.toml | pyproject.toml |
Practical recommendations drawn from the existing code:
- Keep connector modules thin: defer I/O and auth to shared helpers so the entry-point refactor (issue #9) remains a drop-in change. Source: oto/commands/secrets.py
- Prefer environment-aware secret lookup (env vars → file provider → Scaleway provider) over hard-coded credentials; this matches the provider rework tracked in issue #3. Source: oto/commands/secrets.py
- When targeting a niche site (for example a conference exhibitor list), model it as a unitary client under
oto/tools/browser/so it can later be extracted into a plugin entry-point likeo_browser.sites, mirroring the v1.5.0oto browser vivatechrelease. Source: pyproject.toml and issue #1 - Declare any heavy dependency as an optional extra (e.g.
oto-cli[vivatech]) rather than a hard requirement, so the core install stays light. Source: pyproject.toml
Roadmap: Entry-Points for Connectors
Issue #9 proposes replacing the glob-based discovery with a Python entry-point group named oto.commands. Each installed package would declare one or more entry-points pointing at importable modules, and oto/cli.py would load them at startup in addition to (or instead of) the bundled files. This unblocks client-specific connectors, simplifies vendor distribution, and keeps the public core small. Until that lands, the only supported way to add a connector remains dropping a module into oto/commands/. Source: docs/create-connector.md and oto/cli.py
Source: https://github.com/otomata-tech/oto-cli / Human Manual
Doramagic Pitfall Log
Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
May increase setup, validation, or first-run risk for the user.
Doramagic Pitfall Log
Found 9 structured pitfall item(s), including 1 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.
1. Installation risk: Installation risk requires verification
- Severity: high
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/otomata-tech/oto-cli/issues/3
2. Configuration risk: Configuration risk requires verification
- Severity: medium
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: capability.host_targets | https://github.com/otomata-tech/oto-cli
3. Capability evidence risk: Capability evidence risk requires verification
- Severity: medium
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: capability.assumptions | https://github.com/otomata-tech/oto-cli
4. Maintenance risk: Maintenance risk requires verification
- Severity: medium
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/otomata-tech/oto-cli
5. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: downstream_validation.risk_items | https://github.com/otomata-tech/oto-cli
6. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: risks.scoring_risks | https://github.com/otomata-tech/oto-cli
7. Security or permission risk: Security or permission risk requires verification
- Severity: medium
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: community_evidence:github | https://github.com/otomata-tech/oto-cli/issues/9
8. Maintenance risk: Maintenance risk requires verification
- Severity: low
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/otomata-tech/oto-cli
9. Maintenance risk: Maintenance risk requires verification
- Severity: low
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Recommended check: Reproduce the official install and quickstart path in an isolated environment.
- Evidence: evidence.maintainer_signals | https://github.com/otomata-tech/oto-cli
Source: Doramagic discovery, validation, and Project Pack records
Community Discussion Evidence
These external discussion links are review inputs, not standalone proof that the project is production-ready.
Count of project-level external discussion links exposed on this manual page.
Open the linked issues or discussions before treating the pack as ready for your environment.
Community Discussion Evidence
Doramagic exposes project-level community discussion separately from official documentation. Review these links before using oto-cli with real data or production workflows.
- Épic — rework secrets côté CLI : providers (keychain/sops) + lookup scop - github / github_issue
- Isoler les connecteurs custom/client du core public via entry-points `ot - github / github_issue
- Browser clients: collective & wttj - github / github_issue
- v1.5.0 - github / github_release
- v1.4.1 — LinkedIn: profil par défaut (--profile optionnel) - github / github_release
- v1.4.0 — LinkedIn outreach (send/connect/login) - github / github_release
- v1.3.0 - github / github_release
- v1.2.0 - github / github_release
- v1.0.0 — CLI toolkit for AI agents - github / github_release
- v0.4.0 — Gmail multi-account, attachments & drafts - github / github_release
- v0.3.0 - github / github_release
- v0.2.0 - github / github_release
Source: Project Pack community evidence and pitfall evidence