Imported from aviatesk/obsidian-tasks-calendar (
AGENTS.md). Install upstream withnpx skills add aviatesk/obsidian-tasks-calendar. Copyright stays with the author.
Development guide
This repository contains an Obsidian plugin called Tasks Calendar that visualizes tasks on an interactive calendar using FullCalendar. It integrates with the Dataview plugin to automatically gather tasks from notes across the vault.
Prerequisites & installation
See README.md for prerequisites and installation instructions.
Build
npm run build # Quick build with type checking (`skipLibCheck` enabled)
Code quality checks
npm run check # Comprehensive check: format + lint + strict type checking
npm run check:format # Check formatting -- included in `npm run check`
npm run check:lint # Check for ESLint errors -- included in `npm run check`
npm run check:tsc # Strict type checking (no `skipLibCheck`) -- included in `npm run check`
Code quality fixes
npm run fix # Auto-format + auto-fix linting (combined)
npm run fix:format # Auto-format code with Prettier -- included in `npm run fix`
npm run fix:lint # Auto-fix ESLint errors -- included in `npm run fix`
Testing
Currently, there are no agent-executable tests available, as testing typically requires manual intervention. Instead, it is recommended to statically ensure that the code works by following these steps:
- Run
npm run buildto verify that the build completes without issues - Run
npm run checkto verify that there are no errors in the code - Run
npm run fixto adjust code style
Development
General guidelines
- Make sure to run the code quality checks after making changes
- During development: Run
npm run buildto verify compilation succeeds - Before finalizing/committing: Run
npm run checkfor comprehensive validation. This runs format check, ESLint (0 warnings) and strict TypeScript type checking (noskipLibCheck) - To fix issues: Use
npm run fixto auto-format and fix linting in one command
- During development: Run
- Keep the plugin small. Avoid large dependencies. Prefer browser-compatible packages.
- Avoid Node/Electron APIs where possible.
Coding style
[!IMPORTANT]: ALWAYS REMEMBER WITH HIGH PRIORITY
-
All code, documentation and comments should be written in English
- If instructions are given in a language other than English, you may respond in that language
- But code/documentation/comments must be written in English unless explicitly requested in the instructions
-
Do not leave unnecessary comments in code
- Instead prefer self-documenting code with clear variable, function names, and data/control flows
-
When writing documentation, avoid excessive decoration. For example, avoid scattering emojis or overusing
**bold formatting. Use these only where truly necessary. -
Use backticks for code references: When writing comments, commit messages, or documentation, wrap code-related terms in backticks (e.g.,
functionName,variableName,file.ts) to distinguish them from regular text. -
Commit messages:
- Do not include the "Generated with Claude Code" footer in commit messages for this project. Keep commit messages focused and concise.
- When writing commit messages, follow the format
component: Brief summaryfor the title. In the body of the commit message, provide a brief prose summary of the purpose of the changes made. Also, ensure that the maximum line length never exceeds 72 characters. When referencing external GitHub PRs or issues, use proper GitHub interlinking format (e.g.,owner/repo#123for PRs/issues).
-
Keep
main.tsminimal: Focus only on plugin lifecycle (onload, onunload, addCommand calls). Delegate all feature logic to separate modules. -
Split large files: If any file exceeds ~200-300 lines, consider breaking it into smaller, focused modules.
-
Use clear module boundaries: Each file should have a single, well-defined responsibility.
-
Prefer
async/awaitover promise chains; handle errors gracefully. -
Minimize
try/catchscope: Only wrap operations that can actually throw errors. Extract the error-prone operation and use early return:// Good: minimal try/catch scope let result; try { result = await dangerousOperation(); } catch (error) { logger.error(`Failed: ${error}`); return; } safeOperation(result); // Bad: unnecessarily wide try/catch try { const result = await dangerousOperation(); safeOperation(result); // Should be outside try } catch (error) { logger.error(`Failed: ${error}`); } -
Generally, efforts to maintain backward compatibility are not necessary unless explicitly requested by users. For example, when renaming field names in data structures, you can simply perform the rename.
See also Obsidian style guide
Logging guidelines
All logging uses the createLogger() helper function from src/logging.ts,
which automatically adds [TasksCalendar.ComponentName] prefixes. Create a
logger instance in each class or component:
import { createLogger } from './logging';
class MyComponent {
private readonly logger = createLogger('MyComponent');
someMethod() {
this.logger.log('Operation completed');
this.logger.warn('Warning message');
this.logger.error('Error message');
}
}
Follow these message format conventions:
Message format
-
In-progress operations: Use present progressive (verb-ing) with ellipsis
- Example:
Indexing 100 documents...,Deleting 5 embeddings... - Indicates ongoing work
- Example:
-
Completed operations: Use past participle (verb-ed)
- Example:
Indexed 100 documents,Deleted 5 embeddings - Pair with the corresponding in-progress message for clarity
- Example:
-
State reporting: Use past participle (verb-ed)
- Example:
Initialized with model-name,Detected WebGPU,WebGL not detected
- Example:
-
Error messages: Use
Failed to <verb>: ${error}- Example:
Failed to tokenize: ${error},Failed to initialize: ${error} - Include relevant context when helpful (e.g., text length, file count)
- Example:
-
Avoid generic standalone words like
completeordone. Instead, use specific past participles that describe what was completed (e.g.,Indexed 100 documentsinstead ofBatch indexing complete)
Log level
- Use
error(): Critical failures that require user attention- Always pair with user-facing notification showing "check console"
- Example: initialization failures, critical errors that stop execution
- Use
warn(): Problems that don't stop overall execution- Example: fallback scenarios (WebGPU → WASM), individual failures in batch operations, missing hardware/features, external service failures with fallback
- Use
log(): Normal operations and informational messages
Commands & settings
- Any user-facing commands should be added via
this.addCommand(...). - If the plugin has configuration, provide a settings tab and sensible defaults.
- Persist settings using
this.loadData()/this.saveData(). - Use stable command IDs; avoid renaming once released.
UX & copy guidelines (for UI text, commands, settings)
- Prefer sentence case for headings, buttons, and titles.
- Use clear, action-oriented imperatives in step-by-step copy.
- Use bold to indicate literal UI labels. Prefer "select" for interactions.
- Use arrow notation for navigation: Settings → Community plugins.
- Keep in-app strings short, consistent, and free of jargon.
Performance
- Keep startup light. Defer heavy work until needed.
- Avoid long-running tasks during
onload; use lazy initialization. - Batch disk access and avoid excessive vault scans.
- Debounce/throttle expensive operations in response to file system events.
Agent do/don't
Do:
- Always verify code quality before finalizing changes:
- During development: Use
npm run buildfor quick compilation checks - Before completing work: Run
npm run checkfor comprehensive validation
- During development: Use
- Provide defaults and validation in settings.
- Write idempotent code paths so
reload/unloaddoesn't leak listeners or intervals. - Use
this.register*helpers for everything that needs cleanup, e.g.:this.registerEvent( this.app.workspace.on('file-open', f => { /* ... */ }) ); this.registerDomEvent(window, 'resize', () => { /* ... */ }); this.registerInterval( window.setInterval(() => { /* ... */ }, 1000) );
Don't:
- Introduce network calls without an obvious user-facing reason and documentation.
- Ship features that require cloud services without clear disclosure and explicit opt-in.
- Store or transmit vault contents unless essential and consented.
Versioning & releases
- Bump
versioninmanifest.jsonandpackage.json(SemVer). - Only update
versions.jsonwhenminAppVersioninmanifest.jsonchanges. Do not add an entry when the minimum app version stays the same — the existing entry already covers all subsequent versions. - Update
CHANGELOG.md: move the Unreleased section contents into a new version section and update the comparison links. - Create a release commit (e.g.,
release: X.Y.Z) and tag it with the version number. The tag must exactly matchmanifest.json'sversion. Do not use a leadingv. - Push the commit and tag. The
release.ymlGitHub Actions workflow automatically builds the plugin, extracts the changelog, and creates the GitHub release withmanifest.json,main.js, andstyles.cssattached. Do not manually rungh release create. - After the initial release, follow the process to add/update your plugin in the community catalog as required.
Security, privacy, and compliance
Follow Obsidian's Developer Policies and Plugin Guidelines. In particular:
- Default to local/offline operation. Only make network requests when essential to the feature.
- No hidden telemetry. If you collect optional analytics or call third-party
services, require explicit opt-in and document clearly in
README.mdand in settings. - Never execute remote code, fetch and eval scripts, or auto-update plugin code outside of normal releases.
- Minimize scope: read/write only what's necessary inside the vault. Do not access files outside the vault.
- Clearly disclose any external services used, data sent, and risks.
- Respect user privacy. Do not collect vault contents, filenames, or personal information unless absolutely necessary and explicitly consented.
- Avoid deceptive patterns, ads, or spammy notifications.
- Register and clean up all DOM, app, and interval listeners using the provided
register*helpers so the plugin unloads safely.
Mobile
- Where feasible, test on iOS and Android.
- Don't assume desktop-only behavior unless
isDesktopOnlyinmanifest.jsonistrue. - Avoid large in-memory structures; be mindful of memory and storage constraints.
References
- Obsidian sample plugin: https://github.com/obsidianmd/obsidian-sample-plugin
- API documentation: https://docs.obsidian.md
- Developer policies: https://docs.obsidian.md/Developer+policies
- Plugin guidelines: https://docs.obsidian.md/Plugins/Releasing/Plugin+guidelines
- Style guide: https://help.obsidian.md/style-guide