Obsidian Publisher is a plugin that publishes Obsidian notes to GitHub for Hugo processing, using the GitHub REST API (via Octokit) for cross-platform compatibility including iOS.
bun install # Install dependencies
bun run dev # Watch mode with source maps
bun run build # Production build (runs typecheck + lint first)
bun run validate # Full validation: types, tests, lint, build
bun test # Run all tests
bun run test:watch # Watch mode for tests
bun run typecheck # Type checking only
bun run format # Auto-fix formatting (Biome)
bun run lint # Lint (Biome)
bun run check # Format + lint combinedAll GitHub operations must use the REST API through Octokit. Never use local Git commands or tools that require shell access — the plugin must work on iOS.
- User triggers publish —
main.tscommand handler - Settings validation —
publisher.tschecks GitHub credentials - Branch/PR creation —
github-service.tscreates feature branch (if PR workflow enabled) - Content processing —
content-processor.tsconverts Obsidian syntax to Hugo markdown - File upload —
github-service.tsuploads markdown and images via GitHub API - PR creation —
github-service.tscreates pull request (if PR workflow enabled)
main.ts— Plugin entry point: registers commands, loads settings, routes to Publisher, handles settings migrationpublisher.ts— Orchestration: two workflows (publishNote()for direct commit,publishNoteWithPR()for branch+PR), batch publishing, frontmatter validationgithub-service.ts— GitHub API wrapper using Octokit. All REST API calls must be iOS-compatiblecontent-processor.ts— Wikilink/image conversion, filename sanitization, frontmatter processingsettings.ts— Plugin settings UI with GitHub connection testtypes.ts— Type definitions:PublisherSettings,PublishResult,BatchPublishResult,ProcessedContent
Direct Commit (usePullRequests = false): Files committed directly to base branch. Legacy mode for backward compatibility.
Branch + PR (usePullRequests = true): Creates timestamped branch (publish/2026-01-08-143022), commits changes, creates PR with labels. Batch publishing uses one branch and one PR for all files. Branch collision handled via createBranchWithRetry() with suffix.
Existing users default to usePullRequests = false (preserves old behavior). New users default to usePullRequests = true. Migration logic in main.ts:loadSettings() checks for undefined usePullRequests field.
- Wikilinks:
[[Page Name]]to[Page Name](page-name.md)|[[Page|Custom]]to[Custom](page-name.md) - Images:
![[image.png]]to - Filename sanitization: Lowercase, spaces to hyphens, remove special chars (keep alphanumeric/hyphens/underscores/dots), collapse consecutive hyphens, trim edges. Empty becomes
untitled - Frontmatter: Removes
statusfield (if configured), merges template fields, ensuresdatefield exists
Add new methods to github-service.ts using Octokit. Follow the try-catch error handling pattern with descriptive Error objects. Use this.settings.repoOwner and this.settings.repoName. Add optional branch parameter for feature branch support. Status code 404 means file doesn't exist; 422 means branch already exists.
Tests use Bun's built-in runner (bun:test) with describe/test/expect API. Test files live alongside source in src/ with .test.ts suffix. Mocks are consolidated in src/test-preload.ts, loaded via bunfig.toml.
Single-file bundle via Bun: entry src/main.ts to output main.js. Externals: obsidian, electron. Bundled: @octokit/rest.
bun version patch bumps version, auto-syncs manifest.json/versions.json, commits, and tags. Tag push triggers GitHub Actions release (.github/workflows/release.yml).
Code style is enforced by Biome. Run bun run check before committing. Type imports come before value imports.