alamion_obsidian-jira-sync/AGENTS.md
Alamoin 0786db1535
Feats
- `Super Simple Time Tracker` plugin format support
- Support of multiple Jira connections.
- `AGENTS.md` file from Obidian plugin template and filled with info about project
- Updated eslint configs to `eslint.config.js` format + linted all the code; added prettier with according config
- localization validator improvement; multiple localization fixes
- many minor fixes
2026-04-29 17:41:24 +03:00

10 KiB

Obsidian Jira Sync - Community plugin for Obsidian

Project overview

  • Plugin ID: jira-sync
  • Name: Jira Issue Manager
  • Target: Obsidian Community Plugin (TypeScript → bundled JavaScript)
  • Entry point: main.ts compiled to main.js and loaded by Obsidian
  • Required release artifacts: main.js, manifest.json, and optional styles.css
  • Min App Version: 1.10.1
  • Author: Alamion
  • Mobile compatible: Yes (isDesktopOnly: false)

Environment & tooling

  • Node.js: use current LTS (Node 18+ recommended)
  • Package manager: yarn (required - package.json defines yarn scripts)
  • Bundler: esbuild (required - esbuild.config.mjs and build scripts depend on it)
  • Types: obsidian type definitions

Install

yarn install

Dev (watch)

yarn run dev

Production build

yarn run build

Localization

yarn run validate_locale_once  # Validate YAML source files
yarn run compile_locale_once  # Compile YAML to JSON

Linting

All three commands must pass without errors:

  1. yarn run format - No Prettier errors
  2. yarn run lint:fix - No ESLint errors
  3. yarn run build - No TypeScript/build errors
  4. yarn run validate_locale_once - No localization errors

File & folder conventions

  • Source lives in src/. Keep main.ts small and focused on plugin lifecycle.
  • Do not commit build artifacts: Never commit node_modules/, main.js, or other generated files.
  • Generated output should be placed at the plugin root. Release artifacts must end up at the top level of the plugin folder in the vault.

Directory structure (src/)

Directory Purpose Key Files
commands/ User commands getIssue.ts, createIssue.ts, updateIssue.ts, updateStatus.ts, addWorkLogBatch.ts, addWorkLogManually.ts, batchFetchIssues.ts
api/ Jira REST API base.ts (core HTTP), auth.ts, issues.ts, projects.ts, self.ts
settings/ Settings tab & components default.ts (defaults), JiraSettingTab.ts, components/*
modals/ UI dialogs IssueSearchModal.ts, JQLSearchModal.ts, IssueWorkLogModal.ts, ProjectModal.ts, IssueTypeModal.ts, IssueStatusModal.ts
file_operations/ File read/write getIssue.ts, createUpdateIssue.ts, commonPrepareData.ts
tools/ Utilities debugLogging.ts, cacheUtils.ts, filesUtils.ts, convertFunctionString.ts, sanitizers.ts, asyncLimiter.ts
postprocessing/ Live Preview/Reading livePreview.ts, reading.ts
default/ Defaults defaultTemplate.ts, defaultIssue.ts, obsidianJiraFieldsMapping.ts
interfaces/ TypeScript types settingsTypes.ts, index.ts
localization/ i18n translator.ts, compiled/*.json, source/*.yaml

Packages used

Package Purpose Usage
obsidian Obsidian API Core plugin, requestUrl, TFile, Plugin etc.
esbuild Bundler esbuild.config.mjs - bundles all deps into main.js
typescript Type safety TypeScript 4.7.4
fs-extra File operations src/tools/filesUtils.ts
yaml YAML parsing Settings validation, field mapping config
highlight.js Code highlighting src/tools/markdownHtml.ts
chokidar File watching Localization compiler watch mode

Logging

  • Location: src/tools/debugLogging.ts:1-19
  • IMPORTANT BUG: Uses process.env.NODE_ENV which is always undefined in Obsidian (no Node.js runtime) - logging is always on in both dev and production
  • Exports: debugLog, debugWarn, debugError
  • Used in: src/api/base.ts for API request/response logging
  • Prefix format: [DEBUG], [DEBUG WARNING], [DEBUG ERROR]
import { debugLog, debugWarn, debugError } from './tools/debugLogging';
debugLog('Request:', { url, method });
debugWarn('Missing field:', fieldName);
debugError('Failed to fetch:', error);

Cache system

  • Maps Jira issue keys to local file paths
  • In-memory cache: issueKeyToFilePathCache (Map in plugin instance)
  • Persisted in settings: settings.issueKeyToFilePathCache
  • Vault event listeners for maintenance (main.ts:105-130):
    • rename: updates cache when file is moved
    • delete: removes from cache when file is deleted

Localization (i18n)

  • Source files: src/localization/source/{lang}/*.yaml
  • Compiled to: src/localization/compiled/{lang}.json
  • Auto-detects locale from window.localStorage.getItem('language')
  • Falls back to en if not found
  • Build-time compilation: src/localization/compiler.js

Pre-commit hooks

  • Uses husky (.husky/pre-commit)
  • Current check: node check-version.js
  • version-bump.mjs - syncs version from package.json to manifest.json and versions.json
# Runs on every commit:
node check-version.js
  • Note: Future pre-commit upgrades may include linting and type checking

Manifest rules

  • Must include:
    • id (stable - never change after release)
    • name
    • version (Semantic Versioning x.y.z)
    • minAppVersion
    • description
    • isDesktopOnly (boolean)
  • Keep minAppVersion accurate when using newer APIs

Testing

  • Manual install for testing: copy main.js, manifest.json, styles.css to:
    <Vault>/.obsidian/plugins/<plugin-id>/
    
  • Reload Obsidian and enable in Settings → Community plugins

Commands & settings

  • Commands added via this.addCommand(...) in src/commands/
  • Settings persisted with this.loadData() / this.saveData()
  • Use stable command IDs - avoid renaming after release
  • All commands wrapped in register*Command functions

Versioning & releases

  • Bump version in manifest.json (SemVer) and update versions.json
  • Run yarn version to auto-bump via version-bump.mjs
  • Create GitHub release with tag matching manifest.json version (no leading v)
  • Attach: manifest.json, main.js, styles.css (if present)

Security, privacy, and compliance

  • Default to local/offline operation. Only make network requests when essential.
  • No hidden telemetry.
  • Never execute remote code, fetch and eval scripts.
  • Minimize scope: read/write only what's necessary inside the vault.
  • Use register* helpers for all listeners to ensure proper cleanup on unload.

Performance

  • Keep startup light - defer heavy work until needed
  • Batch disk access, avoid excessive vault scans
  • Debounce/throttle operations in response to file system events

Coding conventions

  • TypeScript with "strict": true preferred
  • Keep main.ts minimal - delegate feature logic to separate modules
  • Split large files (~200-300+ lines) into smaller focused modules
  • Bundle everything into main.js (no unbundled runtime deps)
  • Prefer async/await over promise chains
  • Handle errors gracefully
  • Do not add comments unless explicitly requested

Agent do/don't

Do

  • Add commands with stable IDs (don't rename after release)
  • Provide defaults and validation in settings
  • Write idempotent code paths
  • Use this.register* helpers for cleanup

Don't

  • Introduce network calls without user-facing reason and documentation
  • Ship features requiring cloud services without opt-in
  • Store or transmit vault contents unless essential

Common tasks

Add a command

export function registerMyCommand(plugin: JiraPlugin): void {
	plugin.addCommand({
		id: 'my-command',
		name: t('name'),
		checkCallback: (checking: boolean) => {
			const valid = validateSettings(plugin);
			if (!checking && valid) doSomething(plugin);
			return valid;
		},
	});
}

Make API request

import { baseRequest } from './api/base';
const issue = await baseRequest(plugin, 'GET', `/issue/${issueKey}`);

Persist settings

await this.saveData(this.settings);

Register listeners safely

this.registerEvent(
	this.app.workspace.on('file-open', (f) => {
		/* ... */
	}),
);
this.registerDomEvent(window, 'resize', () => {
	/* ... */
});
this.registerInterval(
	window.setInterval(() => {
		/* ... */
	}, 1000),
);

Troubleshooting

  • Plugin doesn't load: ensure main.js and manifest.json at top level of plugin folder
  • Build issues: run yarn run dev or yarn run build to compile
  • Commands not appearing: verify addCommand runs after onload and IDs are unique
  • Settings not persisting: ensure loadData/saveData are awaited

References