NicAI shared tools

The 30 small Python wrappers my NicAI skills call for research, web data, media, publishing, email, DNS and home automation, and the pattern they share.

Skills tell an agent what to do. Shared tools are how it reaches the outside world: small Python scripts, 1 per service, in a single folder at ~/ai/_shared/. Every project in my workspace calls the same copy.

There are 30 Python files in that folder today. 29 are tools with a command line, and 1 (env_loader.py) is the helper that loads API keys for the others. This note lists 27 of them: 3 work-only tools stay private.

The pattern

Where 1 folder, ~/ai/_shared/, used by work, personal and lab projects alike
Keys 1 file, _shared/.env, for every API key. An environment variable wins if it is already set
Language Python, standard library first: 26 of the 30 import nothing outside it
Interface A CLI for the agent, plus functions other scripts can import
Scraping Through a SOCKS5 proxy, only for scraping, never for API calls
Size 39 to 883 lines each. Small enough for an agent to read before it uses one

Why it is built this way:

  • One place for keys. A rotated key changes in 1 file, and every project picks it up. Agents may read variable names, never print values.
  • Stdlib first. A script that needs only urllib and json runs on any Mac with Python, with nothing to install. Only 4 scripts import a third-party package: calendar parsing, HTML to Markdown, image resizing and the proxy. yt.py also drives the yt-dlp command-line tool.
  • CLI for agents. An agent can run python3 ~/ai/_shared/perplexity.py "query" without knowing anything about the API behind it. The docstring at the top of each file is the manual.
  • Importable for scripts. pageimages.py imports the crawler and the proxy helper instead of rewriting them. send_email.py imports the mail helper.

The skills lean on them: 23 skills reference a shared tool by path. The most used by far is sql.py, the SQLite wrapper behind most database lookups.

Research

Tool What it is for
perplexity.py Web research with citations, through Perplexity's Sonar models
grok.py Research on live X posts and the web through xAI's Grok, plus image generation
apollo.py Company data enrichment from a domain, through Apollo.io
knowledgeowl.py Mirrors Kaltura's public Knowledge Centre to Markdown, with full-text search

Web data

Tool What it is for
firecrawl.py Scrapes 1 or more URLs to Markdown through Firecrawl
cloudflare.py Crawls a site to Markdown through Cloudflare's browser rendering, for pages that need JavaScript
pageimages.py Harvests a page's own content images, filters logos and trackers, and ranks the rest for a human to pick
proxy.py The SOCKS5 proxy helpers for any script that scrapes

Media

Tool What it is for
yt.py YouTube metadata, transcripts, chapters, audio or video, through yt-dlp
tts.py Text to speech through ElevenLabs, as .mp3 for videos
imagekit.py Uploads images and builds resized URLs, so no page ever serves a full-size file

Publishing

Tool What it is for
publish_nicai.py Publishes a page or folder to nicailab.com. See What is NicAIlab
publish_kc.py Publishes decks, avatar demos and one-pagers to kaltura.cloud
kc_demo_index.py Builds the index page of my live avatar demos on kaltura.cloud

Both publishers give each project an unguessable link segment. It isn't authentication, just a link that works only if I gave it out.

Email, calendar and chat

Tool What it is for
calendar.py Reads my published Outlook calendar and lists free slots
ics_future.py Trims that calendar to future events for the feed my booking page reads
cal.py My cal.eu booking account: event types, open slots, bookings
migadu.py Read-only access to my personal mailboxes, plus a sender denylist for spam
send_email.py Sends a plain-text email and files a copy in Sent

DNS and home

Tool What it is for
ionos.py DNS records for nicolasdeville.com: list, add, update
spaceship.py DNS records for kaltura.cloud: list, add, merge
ha_ws.py A minimal WebSocket client for Home Assistant, in the standard library only
ma_ws.py The same for Music Assistant
ha_camera_feed_listener.py Waits for a Home Assistant event and opens a matching view on my Mac

Utilities

Tool What it is for
env_loader.py Loads keys from _shared/.env for every other tool
sql.py A drop-in sqlite3 CLI with CSV output. Reads return rows, writes return a count
client_init.py The only write path into my client notes folder: creates new, never overwrites

client_init.py shows a pattern I now use for anything that writes into a folder I care about. The tool can do exactly 1 thing, checks every input before the first write, and refuses whatever it can't prove safe. An agent can't break what the tool doesn't let it touch.

What works, what doesn't

What works:

  • Swapping a service is cheap. A skill calls perplexity.py, not Perplexity. If I change provider, I change 1 script.
  • Read-only by default. The mail tools open mailboxes read-only and never delete. Sending email is a separate script with a dry-run mode, and my agents run it only when I tell them to send.
  • The docstring is the manual. Most files open with usage examples, so an agent reads the top of the file and runs it. No separate documentation to keep in sync.

What doesn't:

  • The folder is a drawer. API wrappers sit next to DNS, home automation and mail tools. Nothing enforces a structure yet.
  • The README lags. It lists 13 tools. The folder holds 30.
  • No tests. Each tool gets checked by use. A silent API change shows up as a failed skill, not a failed test.

What's next

  • Bring the README back in line with the folder. Generating it from the docstrings would stop it drifting again.
  • Give each tool a smoke test that runs without spending API credits.
NicAI
Written by NicAI, Nic's AI assistant, for his personal knowledge base. Researched and drafted by the model, not hand-written by Nic. Verify anything you plan to act on.