Buy movie tickets in Colombia from the terminal — Royal Films, Cine Colombia, Cinemark. Agent-first, up to the payment link (never charges).
Buy movie tickets in Colombia from the terminal, across 3 chains — Royal Films, Cine Colombia and Cinemark. Built for an agent to operate and a human to supervise.
Browse cities, cinemas, billboard, showtimes and the seat map; and take the purchase up to the payment link. The CLI never charges: it generates the link (PSE, ePayco or PlacetoPay) and you pay at your bank.
No npm account needed — install straight from GitHub. Bun is the simplest (installs clean, no flags):
bun add -g github:estevg/cinesco-cli # recommended
With npm you must pass --install-links (npm 11.x otherwise leaves a broken symlink):
npm i -g --install-links github:estevg/cinesco-cli
Or run it once without installing:
npx github:estevg/cinesco-cli doctor
Re-run the same command to update. cinesco doctor tells you what's present, what's missing, and the command that fixes it.
Cine Colombia is protected by Cloudflare + reCAPTCHA, so its login and checkout run through a real browser, via agent-browser. Royal Films and Cinemark are 100% headless — no browser needed.
npm i -g agent-browser # all platforms
brew install agent-browser # macOS
agent-browser install # downloads Chrome, first time only
bun install
bun run build # bundles dist/cinesco.js and dist/royalfilms.js (Node targets)
node dist/cinesco.js doctor
Optional native binaries (no Node/Bun needed): bun run build:binaries → binaries/.
cinesco --help # the full command surface (alias for `schema`)
cinesco doctor # what can I use right now
cinesco providers # the three chains
# search a movie across all three chains at once (lead with the movie, not the chain)
cinesco search "spider-man" --city bogota
# browse (headless, no login). Start with `regions`: Royal Films and Cinemark
# take the region ID it returns, not a city name.
cinesco cinemark regions # cities + their IDs (e.g. bogota, soledad)
cinesco cinemark movies bogota
cinesco cinemark showtimes 109320 bogota --date viernes # natural dates: hoy | mañana | <weekday>
# buy — interactive wizard for a human…
cinesco start
# …or non-interactive for an agent/script (credentials via env vars):
CINEMARK_EMAIL=you@mail.com CINEMARK_PASSWORD=... \
cinesco cinemark order --cinema 2401 --session 151754 --seats F6 \
--movie 109320 --region bogota --bank 1007 --json
# → { orderId, total, seats, paymentUrl }. The CLI never charges — it stops at the link.
Output is JSON when stdout is not a terminal, so an agent gets parseable data without
passing --json. On a terminal you get tables and colour.
An agent doesn't drive the interactive wizard — it calls the --json commands and holds
the conversation itself, filling slots (city → movie → cinema → day → time → seat) and
asking only for what's missing. From "I want to see Spider-Man in Bogotá on Friday" it
runs search → showtimes --date viernes → seats → order and hands back the payment
link. The full recipe + example dialogue lives in the agent skill:
npx skills add estevg/cinesco-cli # install the skill
cinesco skills # or read the manual straight from the binary
| Chain | Browse | Login | Browser | Payment |
|---|---|---|---|---|
| Royal Films | ✅ | email+password → JWT | no | ePayco |
| Cinemark | ✅ | email+password → 24h token | no | PSE / PayU |
| Cine Colombia | ✅ | browser (Cloudflare + reCAPTCHA) | agent-browser | PlacetoPay |
cinesco --help | schema # documented surface (--help, -h, help all alias to schema)
cinesco <chain> --help # per-chain help, scoped to that chain (also `cinesco <chain>`)
cinesco doctor | providers | skills | start
cinesco search "<movie>" --city <city> # cross-chain movie search
cinesco <chain> regions # cities + their IDs — start here (Royal Films/Cinemark need the ID)
cinesco <chain> cinemas [region] | movies <region>
cinesco <chain> showtimes <movieId> <region> [--date hoy|mañana|<weekday>|YYYY-MM-DD]
# every row of `showtimes` carries the cinema/hall/session/movie ids the purchase commands need
# sessions
cinesco <chain> login | status # save/inspect a session (Royal Films, Cine Colombia)
# agent-ready purchase (--json; log in once with `cinesco <chain> login`, or set <CHAIN>_EMAIL / <CHAIN>_PASSWORD):
cinesco <chain> seats --cinema <id> --session <id> [--hall <id>] # free seats + per-seat price (--hall: Royal Films)
cinesco <chain> fares --cinema <id> --session <id> [--hall <id>] # ticket types + price
cinesco <chain> order --cinema <id> --session <id> --seats F6 --movie <id> --region <city> [--hall <id>] [--bank 1007]
cinesco <chain> order ... --dry-run # price the seats without reserving (no hold, no link)
# manage
cinesco royalfilms pending # in-process sales (Royal Films)
cinesco royalfilms cancel <reservaId> # release a stuck seat hold
cinesco cinecolombia cancel <orderId> # cancel an order (Cine Colombia)
# chain = royalfilms | cinecolombia | cinemark
cinesco doctor lists what's installed/logged-in and the command that fixes each gap.
Run cinesco skills for the agent manual served by the binary itself. Each chain's
--help prints its own banner and only the commands that chain supports.
~/.cinesco and ~/.royalfilms (mode 600). The password is
never stored — only the resulting token.api.ipify.org (returns your public IP, required by
Cinemark's PSE payment). Nothing is transmitted to whoever publishes the CLI.Clean Architecture: domain (entities + ports) → application (use cases: BrowseCatalog,
PurchaseTickets) → infrastructure (one adapter per chain + a shared HTTP client) →
presentation (CLI + wizard). Adding a chain is writing an adapter that implements
CatalogPort (and PurchasePort if it sells) and registering it.
MIT.