ship.md is the macOS menu bar app name and routing document name for this project. It watches a root folder called ship (recommended: ~/ship) and routes inventory files based on ship.md documents.
The interface is intentionally agent-native: places are folders, things are files, and moving a file expresses the intent to move its physical counterpart. That means an agent does not need a proprietary logistics protocol—it can use the filesystem operations it already understands.
What it does:
- Watches a root folder called
ship. - Prompts for
locationandemailwhen a new direct child folder is created. - Treats any
ship.mdinside watched folders as routing context. - Reads inventory filenames and contacts from
ship.md. - When a
.zipfile is dropped into a watched folder, it unzips it, inspects filenames, and moves matching inventory files. - When images are dropped, it sends the image plus all
ship.mdcontext to the Nous inference API. - If a text file says quantities like
we have 10 apples, those quantities are indexed in SQLite and move with the file. - Uses tool-style movement actions:
mv,sendUberDelivery,sendWhatsapp,sendEmail,makeCall,showToast. - Detects filesystem moves done by Finder or command line.
- Writes audit trails to JSON.
- Logs each configured email, WhatsApp, and call webhook as correlated
webhook_attempted,webhook_succeeded, orwebhook_failedaudit events. - Indexes
## Webhookdefinitions from everyship.mdin SQLite. Live file events invoke applicable webhooks from the root down to the nearest folder; startup backfills only index them.
Recommended paths:
- Watched root:
~/ship(setSHIP_ROOT_PATH=~/ship; the legacy compatibility withCP_ROOT_PATHremains available) - Support/config:
~/ship/.ship/ - Config, audit trail, inventory, and webhook index:
~/ship/.ship/inventory.db
On first launch, the app copies any missing demo files into ~/ship, then builds the
SQLite config, inventory, and webhook tables from those files without firing webhooks.
The audit table stays empty until activity happens after initialization. Every stored
row is stamped with the same version as the installed macOS app.
After bootstrapping the demo, you can ask Codex in plain language:
Move the Spanish jersey to the office.
Codex can find the seeded clothes/spanish-jersey.png inventory file and perform the corresponding
auditable move:
python3 -m ship mv ~/ship/clothes/spanish-jersey.png ~/ship/clothes/office/ \
--message "Move the Spanish jersey to the office"And it will. ship.md records the move, resolves the nearest manifests, updates inventory state,
and invokes any delivery or notification actions configured for the route. The same workflow can
start from Codex, Finder, a shell mv, or another program that manipulates the watched filesystem.
ship.md was designed and implemented with Codex powered by GPT-5.6. It was used throughout the project as both a coding collaborator and an operator:
- Turning the filesystem-as-logistics idea into an implementation plan.
- Inspecting and modifying the Python service, watcher, manifests, webhooks, and admin UI.
- Writing regression tests and running them after changes.
- Debugging the macOS app, PKG, DMG, uninstall, and reinstall flows.
- Reviewing diffs and keeping the README aligned with the behavior of the app.
- Operating ship.md directly—for example, moving the Spanish jersey to the office from a natural-language request.
The repeatable development workflow was treated as a Codex skill:
- Uninstall the currently installed macOS app.
- Build and reinstall the latest local version.
- Exercise the app and run its automated tests.
- Inspect the diff and draft a logical commit plan.
- Create the commits and push the branch.
This is also the product thesis in miniature: give an agent understandable files, clear Markdown context, and ordinary tools, and it can operate a useful real-world workflow without a bespoke UI.
Example:
# Warehouse ship.md
## Inventory
- laptop
- monitor
- contract
## Contacts
- email: ops@example.com
- whatsapp: +15551234567
- call: +15557654321If an arriving file name matches one of the inventory items, ship.md can move it into that folder and notify contacts.
Webhook definitions may use ${ENV_VAR} for secrets and {{ context.* }}, {{ event.* }},
or {{ inventory }} templates. Authorization headers are redacted from audit logs.
cd ship
export SHIP_ROOT_PATH=~/ship
python3 -m pip install -r requirements.txt
python3 -m ship bootstrap
python3 -m ship location-endpoint warehouse-a --email-endpoint https://example.com/email --whatsapp-endpoint https://example.com/whatsapp --call-endpoint https://example.com/call
python3 -m ship add-subscriber warehouse-a --email ops@example.com --whatsapp +15551234567 --phone +15557654321
python3 -m ship runcd ship
make buildUseful targets:
make clean
make build
make reinstallArtifacts:
dist/ship.md.appdist/ship-md-installer.pkgdist/ship-md-installer.dmgdist/Uninstall ship.md.command
make reinstall will uninstall the current system app, install the freshly built package, and launch ship.md.
To distribute a disk image installer:
- run
make build - open
dist/ship-md-installer.dmg - inside the mounted image, use
Open Installer.commandfor a one-click install/reinstall - or double-click
ship-md-installer.pkgdirectly README.txtinside the mounted image explains install, reinstall, legacy receipt cleanup, and uninstall flowscripts/reinstall-ship-md.commandnow prefers the DMG helper whendist/ship-md-installer.dmgis available
python3 -m ship bootstrappython3 -m ship runpython3 -m ship headlesspython3 -m ship show-configpython3 -m ship show-auditpython3 -m ship admin --host 127.0.0.1 --port 8765python3 -m ship location-endpoint <location> --email-endpoint URL --whatsapp-endpoint URL --call-endpoint URLpython3 -m ship add-subscriber <location> --email you@example.com --whatsapp +1555... --phone +1555...python3 -m ship mv <from> <to> --message "operator requested move"
HERMES_PORTAL_API_KEYfor image recognition and movement-planning inference.SHIP_ROOT_PATHto set the watched root (for example~/ship). LegacyCP_ROOT_PATHis also still supported.SHIP_SUPPORT_DIRorCP_SUPPORT_DIRto override config storage. By default, state is stored in.ship/under the watched root.SHIP_EMAIL_ENDPOINT/CP_EMAIL_ENDPOINTSHIP_WHATSAPP_ENDPOINT/CP_WHATSAPP_ENDPOINTSHIP_CALL_ENDPOINT/CP_CALL_ENDPOINTSHIP_VISION_MODEL/CP_VISION_MODEL
The audit JSON includes events like:
folder_registeredship_updatedzip_extractedfile_observedmovement_executedservice_startedservice_stopped
The project includes a lightweight admin portal for operators to inspect runtime state.
Run it with:
python3 -m ship admin --host 127.0.0.1 --port 8765Then open http://127.0.0.1:8765 in a browser.
Views:
- Dashboard with summary counts and recent activity
- Inventory table backed by
inventory.db - Audit log viewer backed by the SQLite
audit_eventstable - Config viewer backed by SQLite configuration tables
JSON endpoints:
/api/summary/api/inventory/api/logs/api/config
The macOS app bundle and installer use:
ship/assets/ship-icon.icnsas the app iconship/assets/ship-icon.pngas the source rendership/assets/trayTemplate.pngas the monochrome menu bar icon
The tray icon is configured as a macOS template image so it adapts to light/dark menu bar appearances.
The macOS installer also ships an uninstaller:
/Applications/Uninstall ship.md.commanddist/Uninstall ship.md.command
Double-clicking it will:
- prompt for confirmation
- stop the running ship.md app if needed
- remove
/Applications/ship.md.app - forget the installer receipt
com.boskykode.shipmd.pkg
It intentionally leaves support data in:
~/ship/.ship/
That keeps audit logs and local state unless you remove them manually.
