README file from
GithubMiYo Hakobi — Obsidian File Ferry
Scheduled file ferry between your Obsidian vault and local filesystem paths. Voice memos / snippets / captures land in your inbox; folders / tags / notes export out to disk. Local-first, no daemon, no network surface.
Part of the MiYo family. The plugin is referred to as MiYo Hakobi in the Obsidian community-plugin index and in the settings UI; "Hakobi" alone is used as a short form throughout this README and the source.
Why MiYo Hakobi?
Most "ferry the files" tooling either (a) lives outside Obsidian and has to be told about your vault separately (Hazel, launchd, cron), or (b) lives inside Obsidian and brings a cloud API along for the ride (Dropbox SDK, Google Drive OAuth, S3 keys). Hakobi is built around a different default:
- No network surface. No ports, no MCP server, no telemetry, no SDKs reaching out. Hakobi reads and writes locally-mounted filesystem paths.
- Approval is the rule, not the run. Creating a rule is the approval moment. After that, ferrying happens silently on each rule's
everyMinutesschedule. - Per-device opt-in by default. Newly-synced rules are off on every device that didn't create them. No surprise multi-device runs producing "Conflicted copy" files.
- Metadata-only audit log. Every run produces NDJSON entries with paths, operations, byte counts, and timings — but never note content, frontmatter values, or absolute home paths. The field allowlist is enforced at compile time.
If you want voice memos, capture-app exports, or Hazel-bait folders to land in your vault on a schedule — and the reverse for tagged or foldered exports — without inviting a cloud API, daemon, or telemetry, Hakobi is for you. External MCP access for your vault is the job of MiYo Kado.
Features
- Two rule types —
import(FS → vault) andexport(vault → FS) - Three export sources —
folder(recursive vault subtree),tag(one or more tags withany/allmatch),note(single vault note) - Per-rule schedule — each rule has its own
everyMinutescadence; one timer per enabled rule - Atomic writes — destination is either the old version or the new version, never partial
- Filename sanitization — NUL bytes, path traversals, and empty names are refused at scan time
- Stability check — import waits for the source's
mtimeto stay quiet forstabilityCheckMsbefore picking it up; no half-written files - Cloud-sync placeholder safe — stalled placeholders are skipped (logged as
io-timeout) instead of force-materialized - Per-device toggle — every rule has an
enabledOnThisDeviceflag stored in a non-synced sibling file - Six command-palette commands — Run / Run-one / Dry-run for both directions
- Audit log — metadata-only NDJSON with monthly rotation, configurable retention and size cap
- Dry-run mode — every rule supports a dry-run flag; audit log records
would-write/would-skip/would-suffixdecisions instead of touching files - Status bar 運 — three-state indicator (idle / running / failed) with sticky-failed acknowledgement on click
Documentation
| Document | Audience | Content |
|---|---|---|
| Installation | Everyone | Community Plugins, BRAT, manual install |
| Configuration Guide | Vault owners | Settings UI walkthrough — General, Import, Export subtabs |
| Example Configurations | Vault owners | Common rule recipes — voice memos, daily journal, tag bundles |
| How It Works | Vault owners + contributors | Architecture, scheduler, audit log, lifecycle |
| Commands | Vault owners | The six command-palette entries and what they do |
| Audit Log | Vault owners | Format, retention, allowlist, NDJSON inspection examples |
| Per-device Enablement | Vault owners | Why your synced rule didn't run; cross-device coordination model |
| Troubleshooting / FAQ | Vault owners | Common issues with concrete fixes |
| Development Guide | Contributors | Build, test, lint, branching, architecture rules |
| Privacy Policy | Everyone | Network surfaces, local storage, audit-log allowlist, supply chain |
Quick Start
- Install the plugin
- Open Settings → MiYo Hakobi
- The General subtab is selected by default — defaults are sensible; leave them be on first run
- Switch to Import or Export and click + Add rule
- Pick source + destination, set
everyMinutes, choosecopy/moveandskip/suffix, save - The status-bar 運 lights up when the first tick fires (within
everyMinutes, plus a 3-second initial-run grace at plugin start)
For ready-made recipes — voice memos, journal export, tag-bundle publish — see Example Configurations.
Screenshots
General subtab — header section (plugin identity + hanko) plus global settings (per-file IO timeout, audit retention / size, stability check window) and the audit-log inspect / purge buttons.
Import subtab — list of import rules. Each row shows the per-device toggle, name + summary, badges (every Nm · copy/move · skip/suffix · mirror/flatten), and an overflow ⋯ menu (Edit / Run now / Run dry-run / Delete).
Export subtab — same shape as Import. Source-type can be folder (recursive vault subtree), tag (one or more tags with any/all match), or note (single vault note).
Roadmap
These are ideas under consideration, not commitments:
- Active-note one-shot export — a fuzzy-suggester command that lists configured export rules and runs the chosen one against the active note.
- File-menu integration — a right-click
Export via rule…entry on notes in the file explorer (PRD F12, deferred from v0.1). - Settings import / export — backup / restore of the rule definitions.
Architecture
NodeFs → VaultIo → AuditLog + Rotation → RuleStore → DeviceStore
→ InFlightRegistry → ImportRunner + ExportRunner → StatusBar
→ Scheduler → SettingsTab → CommandRegistry
Layered, downward-only dependency flow. The domain layer (validation, sanitization) is pure — no obsidian import, no node:fs — so the entire validation model is testable without either runtime. See How It Works for the full architecture.
What Hakobi does NOT do
The following are explicitly out of scope for v0.1 and will probably never arrive:
- No external network surface. No ports, no MCP server, no inbound HTTP, no IPC socket. (External MCP access to your vault is the job of MiYo Kado.)
- No native cloud-service APIs. No Dropbox HTTP, no Google Drive REST, no S3, no SFTP, no WebDAV. Hakobi only reads and writes locally-mounted FS paths. Cloud-sync folders that mount as local paths (Dropbox, iCloud Drive, OneDrive, Google Drive's local mirror, Syncthing) are in scope as plain local paths — your trust decision.
- No mobile support.
isDesktopOnly: true. - No per-execution approval prompts. Creating the rule IS the approval.
- No LLM / AI integration of any kind, even passively.
- No coupling to other MiYo components (Tomo, Hashi, Kado, Seigyo) in v0.1.
- No daemon / system-service mode. Hakobi runs only while Obsidian is open.
- No cron expressions. Only
everyMinutes. - No make-up runs for ticks missed while Obsidian was closed or the machine was asleep.
- No forced materialization of cloud-sync placeholder files. Stalled placeholders are skipped + logged.
- No telemetry, analytics, or crash reporting. Ever. See Privacy Policy.
Part of MiYo
Hakobi is part of MiYo, a small family of Obsidian-adjacent tools focused on giving you control over what your assistants and your filesystem can see and do. Hakobi is the file-ferry component — the piece that moves bytes between your vault and disk on a schedule. Sibling components handle different concerns:
- MiYo Kado — security-first MCP gateway.
- MiYo Tomo / MiYo Tomo Hashi — Claude Code AI workflows + Obsidian session UI.
Open tracking
Live issues live in GitHub Issues.
Support
If MiYo Hakobi is useful to you and you want to help me keep building, you can support development via:
Issues and pull requests are also very welcome.
Contributing
Contributions are welcome. The short version:
- Open an issue first for anything non-trivial (bugs, features, refactors) so we can align on scope before you invest time.
- Fork & branch from
main. Use a descriptive branch name (e.g.fix/import-stability-check,feat/file-menu-export). - Keep changes focused — one feature or one fix per PR. See Development Guide for build, test, and lint commands.
- Tests & lint must pass — run
npm run build,npm test, andnpm run lintbefore pushing. - Conventional commits —
feat:,fix:,docs:,refactor:. Release notes are generated from commit history. - Open a PR against
mainand reference the issue. Small, reviewable diffs get merged fastest.
For security issues, please do not open a public issue — email [email protected] instead.